dotnet/efcore · error · InvalidOperationException

The key on the entity type ' ' cannot be configured because…

Error message

The key {keyProperties} on the entity type '{entityType}' cannot be configured because the property '{property}' is contained in a complex type mapped to a JSON column. Keys cannot reference properties that are stored inside a JSON document.

What it means

ValidateKey throws KeyPropertyInJsonComplexType when any property of a key is declared on a complex type that is mapped to a JSON column. Keys are relational concepts that must map to real columns; a property stored inside a JSON document cannot participate in a primary/alternate key, so the validator blocks this at finalization.

Solutions

  1. Move the key property out of the JSON-mapped complex type onto the owning entity as a real column.
  2. Drop the HasKey call referencing properties inside the JSON complex type; keys cannot live in JSON.
  3. If you need identity over JSON content, store a derived real column (e.g. a hash) and key on that instead.

Example fix

// before
modelBuilder.Entity<Customer>()
    .OwnsOne(c => c.Address, a =>
    {
        a.ToJson("address");
        a.Property(p => p.PostalCode);
    });
modelBuilder.Entity<Customer>().HasAlternateKey(c => c.Address.PostalCode); // throws

// after — promote to a real column on Customer
modelBuilder.Entity<Customer>().Property(c => c.PostalCode).HasColumnName("postal_code");
modelBuilder.Entity<Customer>().HasAlternateKey(c => c.PostalCode);
Defensive patterns

Strategy: validation

Validate before calling

foreach (var keyProp in key.Properties)
    if (keyProp.DeclaringType is IComplexType ct && ct.IsMappedToJson())
        throw new InvalidOperationException($"Key property {keyProp.Name} is in a JSON complex type.");

Type guard

static bool KeyReferencesJsonProperty(IKey k)
    => k.Properties.Any(p => p.DeclaringType is IComplexType ct && ct.IsMappedToJson());

Prevention

When it happens

Trigger: Defining a key (HasKey) where one of the key properties lives on a ComplexType whose ComplexProperty is configured with ToJson. The check iterates key.Properties and inspects each property.DeclaringType — if it is IComplexType && complexType.IsMappedToJson(), the key is rejected.

Common situations: Promoting a nested JSON property to part of a key after switching to ToJson mapping; scaffolding code that adds keys to complex types before configuring JSON; value objects used as keys then migrated into a JSON column.

Related errors


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

Appendix: source

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

        {
            throw new InvalidOperationException(
                RelationalStrings.AutoLoadedJsonProperty(property.Name, structuralType.DisplayName()));
        }
    }

    /// <inheritdoc />
    protected override void ValidateKey(
        IKey key,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {
        base.ValidateKey(key, logger);

        foreach (var property in key.Properties)
        {
            if (property.DeclaringType is IComplexType complexType
                && complexType.IsMappedToJson())
            {
                throw new InvalidOperationException(
                    RelationalStrings.KeyPropertyInJsonComplexType(
                        key.Properties.Format(),
                        key.DeclaringEntityType.DisplayName(),
                        property.Name));
            }
        }

        ValidateDefaultValuesOnKey(key, logger);
        ValidateValueGeneration(key, logger);
    }

    /// <summary>
    ///     Validates a primitive collection property.
    /// </summary>
    /// <param name="property">The property to validate.</param>
    /// <param name="logger">The logger to use.</param>
    protected override void ValidatePrimitiveCollection(
        IProperty property,

View on GitHub (pinned to 3a2006ef56)