dotnet/efcore · error · InvalidOperationException

The entity type ' ' does not have a property mapped to the…

Error message

The entity type '{entityType}' does not have a property mapped to the 'id' property in the database. Add a property mapped to 'id'.

What it means

Thrown when a document-root entity type has a primary key but no property mapped to the Cosmos JSON 'id' property. Cosmos requires every document to have a string 'id' field, so EF Core requires each root entity to expose one (often the PK converted to string, or a shadow id). The validator scans GetProperties() for one whose GetJsonPropertyName() equals the well-known id JSON name and throws if none exists.

Solutions

  1. Ensure at least one property is mapped to the JSON 'id' name - typically the PK with a string conversion: modelBuilder.Entity<T>().HasKey(...).HasConversion<string>() or rely on the built-in id convention.
  2. If you want the PK itself to serve as id, configure its JSON property name to 'id' (GetJsonPropertyName) and ensure a string converter.
  3. Call HasShadowId on the root if you want EF to manage a shadow id property.
  4. Verify you have not disabled the CosmosJsonIdConvention or removed the id mapping in OnModelCreating.

Example fix

// before
modelBuilder.Entity<Thing>()
    .ToContainer("Things")
    .HasKey(t => t.Number);   // int PK, no string 'id'

// after
modelBuilder.Entity<Thing>()
    .ToContainer("Things")
    .HasKey(t => t.Number);
modelBuilder.Entity<Thing>().Property(t => t.Number).HasConversion<string>().ToJsonProperty("id");
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in dbContext.Model.GetEntityTypes().Where(e => e.IsDocumentRoot()))
{
    var hasId = et.GetProperties().Any(p => p.GetJsonPropertyName() == CosmosJsonIdConvention.IdPropertyJsonName);
    if (!hasId) throw new InvalidOperationException($"{et.DisplayName()} missing 'id' mapping");
}

Prevention

When it happens

Trigger: Defining an entity with HasPrimaryKey but never mapping a property to 'id' - e.g. configuring an int PK without HasConversion to string and without the conventional id-mapping shim, or removing the default id mapping. Fires during model validation for any document-root entity.

Common situations: Customizing the primary key without ensuring a string 'id' mapping; setting ToProperty("id") incorrectly; turning off conventions that auto-create the id shadow property; new entity type that the conventions did not wire up an id for.

Related errors


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

Appendix: source

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

    ///     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 ValidateKeys(
        IEntityType entityType,
        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
    {
        var primaryKey = entityType.FindPrimaryKey();
        if (primaryKey == null
            || !entityType.IsDocumentRoot())
        {
            return;
        }

        var idProperty = entityType.GetProperties()
            .FirstOrDefault(p => p.GetJsonPropertyName() == CosmosJsonIdConvention.IdPropertyJsonName);
        if (idProperty == null)
        {
            throw new InvalidOperationException(CosmosStrings.NoIdProperty(entityType.DisplayName()));
        }

        var idType = idProperty.GetTypeMapping().Converter?.ProviderClrType
            ?? idProperty.ClrType;
        if (idType != typeof(string))
        {
            throw new InvalidOperationException(
                CosmosStrings.IdNonStringStoreType(idProperty.Name, entityType.DisplayName(), idType.ShortDisplayName()));
        }

        var partitionKeyPropertyNames = entityType.GetPartitionKeyPropertyNames();
        if (partitionKeyPropertyNames.Count == 0)
        {
            logger.NoPartitionKeyDefined(entityType);
        }
        else
        {
            if (entityType.BaseType != null

View on GitHub (pinned to 3a2006ef56)