dotnet/efcore · error · InvalidOperationException

The property ' ' cannot be configured as…

Error message

The property '{keyProperty}' cannot be configured as 'ValueGeneratedOnUpdate' or 'ValueGeneratedOnAddOrUpdate' because it's part of a key and its value cannot be changed after the entity has been added to the store.

What it means

Thrown by ValidateMutableKey when a property participating in a primary/alternate key has ValueGenerated.OnUpdate (ValueGeneratedOnUpdate or ValueGeneratedOnAddOrUpdate) and is not an ordinal key property (the rare TPT/sequence-style exception). Key values must be immutable once the entity exists; allowing the store to regenerate them on update would break identity tracking.

Solutions

  1. Use ValueGeneratedOnAdd (not OnAddOrUpdate/OnUpdate) for key columns generated by the store on insert: builder.Property(p => p.Id).ValueGeneratedOnAdd().
  2. If the property must not be regenerated, set ValueGenerated.Never.
  3. Verify the key composition — if the offending property is unnecessarily part of the key, remove it from the key.

Example fix

// before
builder.Property(o => o.OrderId)
    .ValueGeneratedOnAddOrUpdate(); // OrderId is the PK
builder.HasKey(o => o.OrderId);

// after
builder.Property(o => o.OrderId)
    .ValueGeneratedOnAdd();
builder.HasKey(o => o.OrderId);
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in model.GetEntityTypes())
{
    foreach (var key in et.GetKeys())
    {
        foreach (var prop in key.Properties)
        {
            if (prop.ValueGenerated.HasFlag(Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.OnUpdate)
                && !prop.IsOrdinalKeyProperty())
            {
                Console.WriteLine($"Key property {et.Name}.{prop.Name} is ValueGenerated.OnUpdate; use ValueGeneratedOnAdd.");
            }
        }
    }
}

Prevention

When it happens

Trigger: builder.Property(p => p.Id).ValueGeneratedOnAddOrUpdate() (or OnUpdate) where p => Id participates in a key. The validator scans key.Properties for any ValueGenerated.HasFlag(ValueGenerated.OnUpdate) and throws unless IsOrdinalKeyProperty() returns true.

Common situations: Misconfiguring an identity column as ValueGeneratedOnAddOrUpdate thinking that helps with updates; copying a generated-column config onto a key; provider convention that accidentally marks a key column with OnUpdate.

Related errors


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

Appendix: source

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

        {
            logger.ModelValidationKeyDefaultValueWarning(propertyWithDefault);
        }
    }

    /// <summary>
    ///     Validates that a key doesn't have mutable properties.
    /// </summary>
    /// <param name="key">The key to validate.</param>
    /// <param name="logger">The logger to use.</param>
    protected override void ValidateMutableKey(
        IKey key,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {
        var mutableProperty = key.Properties.FirstOrDefault(p => p.ValueGenerated.HasFlag(ValueGenerated.OnUpdate));
        if (mutableProperty != null
            && !mutableProperty.IsOrdinalKeyProperty())
        {
            throw new InvalidOperationException(CoreStrings.MutableKeyProperty(mutableProperty.Name));
        }
    }

    /// <summary>
    ///     Validates a single table and all entity types mapped to it.
    /// </summary>
    /// <param name="mappedTypes">The entity types mapped to the table.</param>
    /// <param name="table">The table identifier.</param>
    /// <param name="logger">The logger to use.</param>
    protected virtual void ValidateTable(
        IReadOnlyList<IEntityType> mappedTypes,
        in StoreObjectIdentifier table,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {
        var nonJsonMappedTypes = mappedTypes.Where(e => !e.IsMappedToJson()).ToList();
        if (nonJsonMappedTypes.Count > 0)
        {
            ValidateSharedTableCompatibility(nonJsonMappedTypes, table, logger);

View on GitHub (pinned to 3a2006ef56)