dotnet/efcore · error · InvalidOperationException

The complex collection property

Error message

The complex collection property '{entityType}.{property}' must be mapped to a JSON column. Use 'ToJson()' to configure this complex collection as mapped to a JSON column.

What it means

ValidatePropertyMapping throws ComplexCollectionNotMappedToJson when a complex property is a collection (complexProperty.IsCollection) but its ComplexType is not mapped to JSON. Relational providers require complex collections to live in a JSON column because there is no general multi-row flattening for complex types; only JSON carries the array semantics.

Solutions

  1. Add .ToJson("column_name") to the OwnsMany configuration for the complex collection.
  2. If you actually want relational one-to-many with a child table, use OwnsMany with a navigation that the model treats as an entity collection (HasOne/HasMany) instead of a complex collection.
  3. Verify the property is genuinely a complex collection (List<ComplexType>) and not an entity collection before applying ToJson.

Example fix

// before
modelBuilder.Entity<Order>()
    .OwnsMany(o => o.Items, i =>
    {
        i.Property(p => p.Sku).HasMaxLength(50);
    }); // throws — no ToJson

// after
modelBuilder.Entity<Order>()
    .OwnsMany(o => o.Items, i =>
    {
        i.ToJson("items");
        i.Property(p => p.Sku).HasMaxLength(50);
    });
Defensive patterns

Strategy: validation

Validate before calling

if (complexProperty.IsCollection && !complexProperty.ComplexType.IsMappedToJson())
    throw new InvalidOperationException("Complex collection must be mapped to JSON; add ToJson().");

Type guard

static bool IsComplexCollectionMappedToJson(IComplexProperty cp)
    => !cp.IsCollection || cp.ComplexType.IsMappedToJson();

Prevention

When it happens

Trigger: Calling OwnsMany (or a complex collection property) without ToJson on the owning configuration. The check is `complexProperty.IsCollection && !complexProperty.ComplexType.IsMappedToJson()`.

Common situations: Migrating from owned collection (one-to-many) to complex collection and forgetting ToJson; scaffolding a complex collection then customizing it without JSON; assuming OwnsMany maps to a child table like before EF9 complex types.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/c8ab7b36f918d98e. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:269

        if (property is { IsPrimitiveCollection: true }
            && property.GetTypeMapping().ElementTypeMapping?.ElementTypeMapping != null)
        {
            throw new InvalidOperationException(
                RelationalStrings.NestedCollectionsNotSupported(
                    property.ClrType.ShortDisplayName(), property.DeclaringType.DisplayName(), property.Name));
        }
    }

    /// <inheritdoc />
    protected override void ValidatePropertyMapping(
        IComplexProperty complexProperty,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {
        base.ValidatePropertyMapping(complexProperty, logger);

        if (complexProperty.IsCollection && !complexProperty.ComplexType.IsMappedToJson())
        {
            throw new InvalidOperationException(
                RelationalStrings.ComplexCollectionNotMappedToJson(
                    complexProperty.DeclaringType.DisplayName(), complexProperty.Name));
        }

        if (!complexProperty.ComplexType.IsMappedToJson()
            && complexProperty.IsNullable
            && complexProperty.ComplexType.GetProperties().All(m => m.IsNullable))
        {
            throw new InvalidOperationException(
                RelationalStrings.ComplexPropertyOptionalTableSharing(complexProperty.ComplexType.DisplayName(), complexProperty.Name));
        }

        if (complexProperty.GetJsonPropertyName() != null)
        {
            if (complexProperty.ComplexType.FindAnnotation(RelationalAnnotationNames.ContainerColumnName)?.Value is string columnName)
            {
                throw new InvalidOperationException(
                    RelationalStrings.ComplexPropertyBothJsonColumnAndJsonPropertyName(

View on GitHub (pinned to 3a2006ef56)