[API reference](https://evolu.dev/docs/api-reference) › [@evolu/common](https://evolu.dev/docs/api-reference/common) › [Type](https://evolu.dev/docs/api-reference/common/Type) › Object

```ts
const Object: createRootType(
  "Object",
  (
    value: unknown,
    options: ValidationOptions = firstValidationOptions,
  ): Result<Readonly<Record<string, unknown>>, PlainObjectError> => {
    if (value === null || typeof value !== "object") {
      return err({
        type: "Object",
        reason: { kind: "NotObject", value },
      });
    }
    if (!isPlainObject(value)) {
      return err({
        type: "Object",
        reason: { kind: "UnexpectedPrototype", value },
      });
    }

    let errors: RuntimeObjectPropertyErrors | undefined;

    for (const key of Reflect.ownKeys(value)) {
      let propertyError:
        ObjectPropertyAccessError | ObjectExcessPropertyError | undefined;

      if (typeof key !== "string") {
        propertyError = { type: "ObjectExcessProperty" };
      } else {
        const descriptor = globalThis.Object.getOwnPropertyDescriptor(
          value,
          key,
        );
        assert(
          descriptor !== undefined,
          "Object property descriptor is missing.",
        );

        if (!("value" in descriptor)) {
          propertyError = {
            type: "ObjectPropertyAccess",
            reason: "Accessor",
          };
        } else if (!descriptor.enumerable) {
          propertyError = {
            type: "ObjectPropertyAccess",
            reason: "NonEnumerable",
          };
        }
      }

      if (propertyError === undefined) continue;

      errors ??= createMutableRecord<string, TypeError>();
      errors[key] = propertyError;
      if (options.errors === "first") break;
    }

    return errors === undefined
      ? ok(value)
      : err({
          type: "Object",
          reason: { kind: "Properties", errors },
        } as PlainObjectError);
  },
  (error: ObjectError) => {
    if (error.reason.kind !== "Properties")
      return formatPlainObjectRootError(error.reason);
    const key = Reflect.ownKeys(error.reason.errors).at(0);
    assertNonNullable(key);
    const propertyError = error.reason.errors[key];
    assertNonNullable(propertyError);
    if (propertyError.type === "ObjectPropertyAccess") {
      switch ((propertyError as ObjectPropertyAccessError).reason) {
        case "Accessor":
          return "An Object property must be a data property. Materialize accessor values into plain data before using this Type or use a different Type.";
        case "NonEnumerable":
          return "An Object property must be enumerable. Make it enumerable or use a different Type.";
      }
    }
    if (propertyError.type === "ObjectMissingProperty")
      return `The required property ${safelyStringifyUnknownValue(key)} is missing.`;
    if (typeof key === "symbol")
      return "An Object property key must be a string. Remove the symbol property or use a different Type.";
    if (propertyError.type === "ObjectExcessProperty")
      return `The property ${safelyStringifyUnknownValue(key)} is not allowed. Remove it or use a different Type.`;
    return `The property ${safelyStringifyUnknownValue(key)} is invalid.`;
  },
  createObjectRuntimeTypeIssues(((error: ObjectError) => {
    if (error.reason.kind !== "Properties")
      return formatPlainObjectRootError(error.reason);
    const key = Reflect.ownKeys(error.reason.errors).at(0);
    assertNonNullable(key);
    const propertyError = error.reason.errors[key];
    assertNonNullable(propertyError);
    if (propertyError.type === "ObjectPropertyAccess") {
      switch ((propertyError as ObjectPropertyAccessError).reason) {
        case "Accessor":
          return "An Object property must be a data property. Materialize accessor values into plain data before using this Type or use a different Type.";
        case "NonEnumerable":
          return "An Object property must be enumerable. Make it enumerable or use a different Type.";
      }
    }
    if (propertyError.type === "ObjectMissingProperty")
      return `The required property ${safelyStringifyUnknownValue(key)} is missing.`;
    if (typeof key === "symbol")
      return "An Object property key must be a string. Remove the symbol property or use a different Type.";
    if (propertyError.type === "ObjectExcessProperty")
      return `The property ${safelyStringifyUnknownValue(key)} is not allowed. Remove it or use a different Type.`;
    return `The property ${safelyStringifyUnknownValue(key)} is invalid.`;
  }) as TypeErrorFormatter<TypeError>),
);
```

Defined in: [packages/common/src/Type.ts:9430](https://github.com/evoluhq/evolu/blob/f0109fb501a593010e858e39248dde1200eeb2d7/packages/common/src/Type.ts#L9430)

A [Type](https://evolu.dev/docs/api-reference/common/Type/interfaces/Type) for readonly plain objects with unknown property values.

`Object` is the runtime counterpart of a `Readonly<Record<string, unknown>>`
data boundary. Its prototype rule uses the realm-neutral structural heuristic
described by [isPlainObject](https://evolu.dev/docs/api-reference/common/Object/functions/isPlainObject). A matching custom root prototype can be
classified as plain; other custom prototypes and class instances are
rejected. Every own property must have a string key and be an enumerable data
property. Accessors, non-enumerable properties, and symbol properties are
rejected without reading their values.

Use [object](https://evolu.dev/docs/api-reference/common/Type/functions/object) when property names are fixed, [record](https://evolu.dev/docs/api-reference/common/Type/functions/record) when keys and
values have their own Types, and [instanceOf](https://evolu.dev/docs/api-reference/common/Type/functions/instanceOf) when an instance belongs
to the domain.