dotnet/efcore · error · InvalidOperationException
The property '{keyProperty}' cannot be configured as 'ValueG
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 that participates in a key has ValueGenerated with the OnUpdate flag set (ValueGeneratedOnUpdate or ValueGeneratedOnAddOrUpdate), unless it is an ordinal key property. Key values are immutable once the entity is stored, so EF forbids configuring a key property as update-generated. Note the validator throws CoreStrings.MutableKeyProperty (shared with the core provider).
Source
Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:500
}
}
}
}
/// <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>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
protected virtual void ValidateDatabaseProperties(
IEntityType entityType,
IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
{
var properties = new Dictionary<string, IPropertyBase>();
foreach (var property in entityType.GetProperties().Where(x => x.IsPersisted()))
{
var jsonName = property.GetJsonPropertyName();
View on GitHub (pinned to dbf9771522)
Solutions
- Remove ValueGeneratedOnUpdate/ValueGeneratedOnAddOrUpdate from the key property; use ValueGenerated.Never or ValueGenerated.OnAdd if a store-generated key is intended.
- Move the update-generated behavior to a non-key property (e.g. an ETag concurrency token mapped to _etag).
- If you need an auto-updating key-like value, use a separate non-key column.
Example fix
// before
modelBuilder.Entity<Doc>()
.Property(d => d.Id)
.ValueGeneratedOnAddOrUpdate();
// after
modelBuilder.Entity<Doc>()
.Property(d => d.Id)
.ValueGeneratedOnAdd(); Defensive patterns
Strategy: validation
Validate before calling
using var ctx = new MyContext();
foreach (var e in ctx.Model.GetEntityTypes())
{
foreach (var key in e.GetDeclaredKeys())
{
foreach (var p in key.Properties)
{
Debug.Assert(!p.ValueGenerated.HasFlag(Microsoft.EntityFrameworkCore.Metadata.ValueGenerated.OnUpdate),
$"{e.Name}.{p.Name} is a key property and must not be ValueGeneratedOnUpdate/AddOrUpdate");
}
}
} Try / catch
try { ctx.Model.GetModel(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("cannot be configured as 'ValueGeneratedOnUpdate'"))
{
logger.LogError(ex, "A key property was configured as update-generated");
throw;
} Prevention
- Never apply ValueGeneratedOnUpdate/ValueGeneratedOnAddOrUpdate to key properties.
- Reserve update-generated columns for non-key fields like ETag/_etag.
- Add a test scanning all keys for the OnUpdate ValueGenerated flag.
When it happens
Trigger: Calling .ValueGeneratedOnUpdate() or .ValueGeneratedOnAddOrUpdate() on a property that is part of a primary key or alternate key.
Common situations: Reusing a relational convention (e.g. row version / update-generated timestamp) on a key column; applying a default value-generation strategy to all properties including keys; copying configuration from a non-key property.
Related errors
- The time to live for analytical store was configured to '{tt
- The default time to live was configured to '{ttl1}' on '{ent
- The provisioned throughput was configured to '{throughput1}'
- The provisioned throughput was configured as manual on '{man
- Cosmos automatic-indexing configuration was set on entity ty
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/5e571b2e11d0712d.
Report an issue: GitHub.