dotnet/efcore · error · InvalidOperationException

The complex collection property '{entityType}.{property}' mu

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 (RelationalModelValidator.cs:267-272) throws when a complex property is a collection (complexProperty.IsCollection) but its complex type is not mapped to JSON. Relational providers require complex collections to be stored as a JSON column (there is no table-per-row mapping for an arbitrary complex collection without an entity key), so the model is rejected unless ToJson() is configured.

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 dbf9771522)

Solutions

  1. Add .ToJson("ColumnName") to the complex collection configuration so it persists as a JSON column.
  2. If you actually want rows in a separate table, use an owned entity collection (OwnsMany with an owned ENTITY type that has identity) instead of a complex type.
  3. Verify the complex type is declared via ComplexType/OwnsMany complex and that ToJson is applied to the collection property.

Example fix

// before
modelBuilder.Entity<Order>().OwnsMany(o => o.Tags, t =>
{
    t.ComplexProperty(p => p.Style); // Tags is a complex collection not mapped to JSON -> throws
});

// after
modelBuilder.Entity<Order>().OwnsMany(o => o.Tags, t =>
{
    t.ToJson("TagsJson");
    t.ComplexProperty(p => p.Style);
});
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in context.Model.GetEntityTypes())
{
    foreach (var cp in et.GetComplexProperties().Where(cp => cp.IsCollection))
    {
        if (!cp.ComplexType.IsMappedToJson())
        {
            // will throw - add .ToJson("col") to this complex collection.
        }
    }
}

Prevention

When it happens

Trigger: Declaring OwnsMany(...) / a complex collection property without calling ToJson() on it. Triggered during model validation when the context first builds.

Common situations: Adding OwnsMany of a value-object-like complex type assuming it maps to a child table (it does not - owned entity collections map to tables, complex collections must be JSON); forgetting the ToJson() call after introducing a complex collection.

Related errors


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