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
- Use ValueGeneratedOnAdd (not OnAddOrUpdate/OnUpdate) for key columns generated by the store on insert: builder.Property(p => p.Id).ValueGeneratedOnAdd().
- If the property must not be regenerated, set ValueGenerated.Never.
- 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
- Default key columns to ValueGeneratedOnAdd; reserve OnUpdate for non-key columns.
- Review key composition whenever you set ValueGeneratedOnAddOrUpdate on a column.
- Add a model-validation test that catches this in CI.
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
- The table ' ' cannot be used for entity type ' ' since it…
- A rows affected parameter, result column or return value…
- An Azure Cosmos DB container name is defined on entity type
- Both ' ' and ' ' are explicitly mapped to the stored…
- Both ' ' and ' ' are mapped to the table ' '. All the…
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)