dotnet/efcore · error · InvalidOperationException

The entity type '{entityType}' has property '{property}' con

Error message

The entity type '{entityType}' has property '{property}' configured as a concurrency token, but only a property mapped to '_etag' is supported as a concurrency token. Consider using 'PropertyBuilder.IsETagConcurrency'.

What it means

Thrown by CosmosModelValidator.ValidateConcurrencyToken when a property is marked IsConcurrencyToken but its JSON property name is not '_etag'. Cosmos DB only supports optimistic concurrency via the system _etag field, so any other concurrency token is meaningless and rejected. The message recommends PropertyBuilder.IsETagConcurrency as the correct API.

Source

Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:741

    }

    /// <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 ValidateConcurrencyToken(
        IProperty property,
        ITypeBase structuralType,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {
        if (property.IsConcurrencyToken)
        {
            var storeName = property.GetJsonPropertyName();
            if (storeName != "_etag")
            {
                throw new InvalidOperationException(CosmosStrings.NonETagConcurrencyToken(structuralType.DisplayName(), storeName));
            }

            var etagType = property.GetTypeMapping().Converter?.ProviderClrType ?? property.ClrType;
            if (etagType != typeof(string))
            {
                throw new InvalidOperationException(
                    CosmosStrings.ETagNonStringStoreType(property.Name, structuralType.DisplayName(), etagType.ShortDisplayName()));
            }
        }
    }

    /// <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 override void ValidateTrigger(

View on GitHub (pinned to dbf9771522)

Solutions

  1. Replace IsConcurrencyToken/IsRowVersion with the Cosmos-specific IsETagConcurrency extension on the property builder.
  2. If you keep a separate property, ensure its JSON property name maps to '_etag' via HasJsonPropertyName("_etag") and that it is the etag concurrency property.

Example fix

// before
modelBuilder.Entity<Item>()
    .Property(i => i.Version)
    .IsRowVersion();

// after
modelBuilder.Entity<Item>()
    .Property(i => i.ETag)
    .HasJsonPropertyName("_etag")
    .IsETagConcurrency();
Defensive patterns

Strategy: validation

Validate before calling

// Fail fast if a concurrency token is not the etag
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    foreach (var prop in et.GetProperties())
    {
        if (prop.IsConcurrencyToken && prop.GetJsonPropertyName() != "_etag")
        {
            throw new InvalidOperationException($"{et.DisplayName()}.{prop.Name} is a concurrency token but not _etag.");
        }
    }
}

Prevention

When it happens

Trigger: Calling builder.Property(x => x.Version).IsRowVersion() or IsConcurrencyToken() on a Cosmos entity without mapping that property to the _etag JSON name.

Common situations: Porting a relational model that uses a RowVersion/Timestamp column for optimistic concurrency. Using a shared entity type across SQL Server and Cosmos where the relational concurrency column is not an etag on Cosmos.

Related errors


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