dotnet/efcore · error · InvalidOperationException

'{entityType1}.{property1}' and '{entityType2}.{property2}'

Error message

'{entityType1}.{property1}' and '{entityType2}.{property2}' are both mapped to column '{columnName}' in '{table}', but have different concurrency token configurations.

What it means

Two properties sharing a column disagree on the IsConcurrencyToken setting (one acts as a row-version token, the other does not). EF Core needs the column's concurrency role to be unambiguous because it affects UPDATE/DELETE WHERE clauses. Thrown from ValidateCompatible.

Source

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

        var currentScale = property.GetScale(storeObject);
        var previousScale = duplicateProperty.GetScale(storeObject);
        if (currentScale != previousScale)
        {
            throw new InvalidOperationException(
                RelationalStrings.DuplicateColumnNameScaleMismatch(
                    duplicateProperty.DeclaringType.DisplayName(),
                    duplicateProperty.Name,
                    property.DeclaringType.DisplayName(),
                    property.Name,
                    columnName,
                    storeObject.DisplayName(),
                    currentScale,
                    previousScale));
        }

        if (property.IsConcurrencyToken != duplicateProperty.IsConcurrencyToken)
        {
            throw new InvalidOperationException(
                RelationalStrings.DuplicateColumnNameConcurrencyTokenMismatch(
                    duplicateProperty.DeclaringType.DisplayName(),
                    duplicateProperty.Name,
                    property.DeclaringType.DisplayName(),
                    property.Name,
                    columnName,
                    storeObject.DisplayName()));
        }

        var currentTypeString = property.GetColumnType(storeObject);
        var previousTypeString = duplicateProperty.GetColumnType(storeObject);
        if (!string.Equals(currentTypeString, previousTypeString, StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException(
                RelationalStrings.DuplicateColumnNameDataTypeMismatch(
                    duplicateProperty.DeclaringType.DisplayName(),
                    duplicateProperty.Name,
                    property.DeclaringType.DisplayName(),

View on GitHub (pinned to dbf9771522)

Solutions

  1. Mark both properties as concurrency tokens (or neither) consistently.
  2. If only one entity needs the token, rename it to a distinct column via HasColumnName.
  3. Move the entity that needs the token to its own table.

Example fix

// before
modelBuilder.Entity<Student>().Property(s => s.Version).IsRowVersion();
modelBuilder.Entity<Teacher>().Property(t => t.Version);
// after
modelBuilder.Entity<Student>().Property(s => s.Version).IsRowVersion();
modelBuilder.Entity<Teacher>().Property(t => t.Version).IsRowVersion();
Defensive patterns

Strategy: validation

Validate before calling

using (var ctx = new MyContext()) { ctx.Model.ToDebugString(); }
var a = ctx.Model.FindEntityType(typeof(Student))!.FindProperty("Version")!.IsConcurrencyToken;
var b = ctx.Model.FindEntityType(typeof(Teacher))!.FindProperty("Version")!.IsConcurrencyToken;
Debug.Assert(a == b, $"Concurrency-token mismatch: {a} vs {b}");

Try / catch

try { using var ctx = new MyContext(); _ = ctx.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("concurrency token configurations"))
{ log.Error("Concurrency-token mismatch on shared column: {Msg}", ex.Message); throw; }

Prevention

When it happens

Trigger: A same-named property on sibling TPH types where one uses IsConcurrencyToken() (or [Timestamp]/IsRowVersion) and the other does not; an owned type whose shared column is a token on one side only; table splitting where only one entity treats the column as a token.

Common situations: Adding optimistic concurrency to one entity in a hierarchy but forgetting the sibling that shares the column; migrating from byte[] RowVersion to uint32 with Xmin where one side forgot to mark the token; misusing [Timestamp] on a shared column.

Related errors


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