dotnet/efcore · error · InvalidOperationException
A partition key is defined on entity type '{entityType}', wh
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 by ValidateKeys when an entity type that has a BaseType (a derived type in an inheritance hierarchy) directly carries the PartitionKeyNames annotation. Partition keys are container-scoped and must be declared on the root entity type of the hierarchy; derived types inherit the partition key. The check uses FindAnnotation to detect a locally-set (not inherited) partition key.
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 dbf9771522)
Solutions
- Move the HasPartitionKey call to the root entity type of the hierarchy.
- Guard shared config helpers with `if (entityType.BaseType == null)` before setting partition keys.
- Remove the partition-key annotation from the derived type.
Example fix
// before modelBuilder.Entity<Manager>().HasPartitionKey(m => m.DepartmentId); // Manager derives from Employee // after modelBuilder.Entity<Employee>().HasPartitionKey(e => e.DepartmentId);
Defensive patterns
Strategy: validation
Validate before calling
using var ctx = new MyContext();
foreach (var e in ctx.Model.GetEntityTypes().Where(t => t.BaseType is not null))
{
Debug.Assert(e.FindAnnotation("Cosmos:PartitionKeyNames") is null,
$"{e.Name} (derived) must not declare a partition key; set it on the root.");
} Type guard
static bool IsHierarchyRoot(Microsoft.EntityFrameworkCore.Metadata.IEntityType e) => e.BaseType is null;
Try / catch
try { ctx.Model.GetModel(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Partition keys must be defined on the root"))
{
logger.LogError(ex, "HasPartitionKey was called on a derived entity type");
throw;
} Prevention
- Only call HasPartitionKey on the root entity of a hierarchy.
- Guard shared config helpers with a BaseType == null check.
- Test that no derived type carries the partition-key annotation locally.
When it happens
Trigger: Calling HasPartitionKey(...) on an EntityTypeBuilder whose entity derives from a base entity (TPH hierarchy sharing a container).
Common situations: Applying a generic 'configure partition key' helper to every entity in a hierarchy; splitting configuration across partial OnModelCreating methods where the derived config runs.
Related errors
- Cosmos automatic-indexing configuration was set on entity ty
- The partition key for entity type '{entityType}' is set to '
- The type of the partition key property '{property}' on '{ent
- 'HasDiscriminatorInJsonId' or 'HasRootDiscriminatorInJsonId'
- 'HasShadowId' was called on a non-root entity type '{entityT
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/769b164b7bf8f33b.
Report an issue: GitHub.