dotnet/efcore · error · InvalidOperationException
A partition key is defined on entity type
Error message
A partition key is defined on entity type '{entityType}', which inherits from '{baseEntityType}'. Partition keys must be defined on the root entity type of a hierarchy. What it means
Thrown when a partition key is configured on a derived entity type (one with a BaseType) rather than on the root of the hierarchy. Cosmos partition keys are a container-level concern and must be defined on the document-root entity type. The validator detects a non-null PartitionKeyNames annotation on a type whose BaseType is not null.
Solutions
- Move the HasPartitionKey call from the derived entity to the document-root entity type of the hierarchy.
- If you use IEntityTypeConfiguration<T>, only register the partition-key configuration for the root type TRoot.
- Remove any HasPartitionKey call on derived types and rely on the root configuration.
Example fix
// before
modelBuilder.Entity<DerivedOrder>() // : Order
.HasPartitionKey(o => o.TenantId);
// after
modelBuilder.Entity<Order>() // the root
.HasPartitionKey(o => o.TenantId); Defensive patterns
Strategy: type-guard
Type guard
// Guard: only configure partition key when the type is the hierarchy root.
static bool IsHierarchyRoot(Type t, IModel model)
{
var et = model.FindEntityType(t);
return et is not null && et.BaseType is null;
}
if (IsHierarchyRoot(typeof(Order), modelBuilder.Model))
modelBuilder.Entity<Order>().HasPartitionKey(o => o.TenantId); Prevention
- Configure partition keys on the document root only.
- Register IEntityTypeConfiguration<T> for the root type only when it includes HasPartitionKey.
- Add a CI test asserting no derived type carries PartitionKeyNames.
When it happens
Trigger: Calling HasPartitionKey on a derived entity (an entity that participates in a TPH hierarchy as a non-root type). Fires during ValidateKeys at model validation time.
Common situations: Applying HasPartitionKey inside a per-derived-type IEntityTypeConfiguration; copying a config that worked for a standalone entity onto a hierarchy member; not realizing partition keys apply to the whole container.
Related errors
- Cosmos automatic-indexing configuration was set on entity…
- 'HasDiscriminatorInJsonId' or…
- 'HasShadowId' was called on a non-root entity type
- The partition key for entity type
- The type of the partition key property
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/769b164b7bf8f33b.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:458
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
&& entityType.FindAnnotation(CosmosAnnotationNames.PartitionKeyNames)?.Value != null)
{
throw new InvalidOperationException(
CosmosStrings.PartitionKeyNotOnRoot(entityType.DisplayName(), entityType.BaseType.DisplayName()));
}
foreach (var partitionKeyPropertyName in partitionKeyPropertyNames)
{
var partitionKey = entityType.FindProperty(partitionKeyPropertyName);
if (partitionKey == null)
{
throw new InvalidOperationException(
CosmosStrings.PartitionKeyMissingProperty(entityType.DisplayName(), partitionKeyPropertyName));
}
var partitionKeyType = (partitionKey.GetTypeMapping().Converter?.ProviderClrType
?? partitionKey.ClrType).UnwrapNullableType();
if (partitionKeyType != typeof(string)
&& !partitionKeyType.IsNumeric()
&& partitionKeyType != typeof(bool))
{View on GitHub (pinned to 3a2006ef56)