Lodash _.toPlainObject() method

Intermediate
⏱️ 6 min read
📚 Updated: May 2026
🎯 3 Code examples
🚀 3 Try-it labs
Lodash

What you’ll learn

  • What _.toPlainObject(value) really does—and the common backwards explanation to ignore.
  • How it walks the prototype chain via _.keysIn to surface inherited enumerable keys.
  • The intended pairing with _.assign for prototype-aware merging.
  • What happens to primitives, strings, arrays, and class instances.

Prerequisites

You can tell own properties (from Object.keys) apart from inherited properties (from a class prototype or Object.create).

  • You know what a plain object means in lodash terms (prototype = Object.prototype or null).
  • Try-it labs load lodash from the CDN.

Overview

One line of implementation: return _.copyObject(value, _.keysIn(value));keysIn includes inherited enumerable keys, so the function flattens the chain rather than strips it.

Inherited → own

Prototype props become own props of the new plain object.

Plain prototype

Result’s prototype is always Object.prototype.

Shallow copy

Nested values are shared references—not deep-cloned.

Syntax

javascript
_.toPlainObject(value)
  • value: the value to convert.
  • Returns: a new plain Object whose own properties are the input’s enumerable keys (own and inherited).
1

The lodash docs example, verified

The official docs show why this function exists: pair it with _.assign when you want inherited keys included in a merge.

javascript
import assign from "lodash/assign";
import toPlainObject from "lodash/toPlainObject";

function Foo() {
  this.b = 2;
}
Foo.prototype.c = 3;

console.log("plain raw:           " + JSON.stringify(toPlainObject(new Foo())));
console.log("assign raw:          " + JSON.stringify(assign({ a: 1 }, new Foo())));        // { a:1, b:2 }
console.log("assign wrapped:      " + JSON.stringify(assign({ a: 1 }, toPlainObject(new Foo()))));  // { a:1, b:2, c:3 }
Try it Yourself
2

Object.create chains flatten too

When an object inherits from a custom prototype object, _.toPlainObject rolls every enumerable inherited key onto the new plain object.

javascript
import toPlainObject from "lodash/toPlainObject";

const proto = { protoProp: "inherited" };
const obj = Object.create(proto);
obj.ownProp = "own";

const flat = toPlainObject(obj);

console.log("flat:                " + JSON.stringify(flat));
console.log("hasOwn protoProp:    " + Object.prototype.hasOwnProperty.call(flat, "protoProp"));
console.log("Object.prototype:    " + (Object.getPrototypeOf(flat) === Object.prototype));
Try it Yourself
3

Primitives, strings, arrays

No keysIn{}. Strings expose indexed character keys but not length (it’s non-enumerable). Arrays behave the same way.

javascript
import toPlainObject from "lodash/toPlainObject";

console.log(
  "null:    " + JSON.stringify(toPlainObject(null)) + "\n" +         // {}
  "42:      " + JSON.stringify(toPlainObject(42)) + "\n" +            // {}
  "'abc':   " + JSON.stringify(toPlainObject("abc")) + "\n" +     // {"0":"a","1":"b","2":"c"}
  "[1,2,3]: " + JSON.stringify(toPlainObject([1, 2, 3]))               // {"0":1,"1":2,"2":3}
);
Try it Yourself

📋 _.toPlainObject vs related operations

API / patternWhat gets copied
_.toPlainObject(x)All enumerable string-keyed properties (own and inherited) onto a new plain object.
{ ...x }Only own enumerable string keys—ignores the prototype chain.
Object.assign({}, x)Same as spread: own enumerable keys only.
_.assign({}, x)Own enumerable keys only (Object.keys).
_.assignIn({}, x)Own and inherited enumerable keys—the close cousin of _.toPlainObject.

Pitfalls to avoid

Direction

It does not strip inherited props

Several blog posts (including older versions of this very page) claim the opposite. The lodash docs are clear: this method flattens inherited keys onto the result.

Depth

Shallow only

Nested objects/arrays are copied by reference. Mutating result.nested will mutate input.nested. Use _.cloneDeep when you need an independent copy.

Non-enumerable

Hidden props are skipped

String’s length, getters defined with { enumerable: false }, and symbol keys are not copied. Only enumerable string-keyed properties make it through.

❓ FAQ

No—it does the opposite. It flattens inherited enumerable string-keyed properties into own properties of the new plain object. This is the entire point of the function.
Spread copies only own enumerable string-keyed properties. _.toPlainObject also walks the prototype chain, so inherited keys land on the result as own keys.
Primitives without enumerable string keys (null, undefined, numbers) return {}. Strings and arrays return their indexed character/element keys—but length is non-enumerable, so it isn't copied.
Yes. _.toPlainObject is shallow—nested objects and arrays are the same references as on the input. Use _.cloneDeep when you also need a deep copy.

Summary

  • Purpose: flatten an object’s prototype-inherited enumerable string keys into own keys of a fresh plain object.
  • Remember: inherited → own, not the other way around. Pair with _.assign for prototype-aware merging.
  • Next: head to Lodash _.toSafeInteger()_.toSafeInteger is up next.
Did you know?

_.toPlainObject uses keysIn under the hood—the same walker as _.assignIn—so it picks up inherited enumerable keys. The output object always has Object.prototype as its prototype, even if the input had a custom one.

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

7 people found this page helpful