dotnet/efcore · error · InvalidOperationException
The discriminator value for
Error message
The discriminator value for '{entityType1}' is '{discriminatorValue}' which is the same for '{entityType2}'. Every concrete entity type mapped to the container '{container}' must have a unique discriminator value. What it means
CosmosModelValidator.ValidateSharedContainerCompatibility throws InvalidOperationException(CosmosStrings.DuplicateDiscriminatorValue) when two instantiable entity types sharing a container are assigned the same discriminator value. EF builds a Dictionary<object, IEntityType> as it iterates and throws on the first duplicate; each concrete type in a shared container must have a unique discriminator value so documents can be routed to exactly one CLR type.
Solutions
- Give every instantiable type in the shared container a distinct discriminator value (e.g. HasValue("order") vs HasValue("invoice")).
- Use a generator or convention that produces unique values (e.g. the entity's simple CLR type name) so manual edits cannot collide.
- If two types share a value intentionally because they are the same shape, merge them or map them via inheritance with a base value.
- Validate the model at startup to surface collisions before any data is written.
Example fix
// before - throws: both types use the same discriminator value
modelBuilder.Entity<Order>()
.ToContainer("Docs")
.HasDiscriminator(o => o.Kind).HasValue("doc");
modelBuilder.Entity<Invoice>()
.ToContainer("Docs")
.HasDiscriminator(i => i.Kind).HasValue("doc");
// after - unique values
modelBuilder.Entity<Order>()
.ToContainer("Docs")
.HasDiscriminator(o => o.Kind).HasValue("order");
modelBuilder.Entity<Invoice>()
.ToContainer("Docs")
.HasDiscriminator(i => i.Kind).HasValue("invoice"); Defensive patterns
Strategy: validation
Validate before calling
// Pre-validate: every shared-container discriminator value must be unique.
static bool DiscriminatorValuesAreUnique(IReadOnlyList<IEntityType> types)
{
var values = types.Where(t => t.ClrType.IsInstantiable() && t.GetContainingPropertyName() is null)
.Select(t => t.GetDiscriminatorValue()).ToList();
return values.Distinct().Count() == values.Count;
} Prevention
- Use a convention that derives the discriminator value from the CLR type name to avoid collisions.
- After merging containers, audit every shared type's discriminator value.
- Avoid copy-paste of HasValue across IEntityTypeConfiguration classes.
- Validate the model at startup to surface collisions before any data is written.
When it happens
Trigger: Two entity types in the same container both call HasValue("default") or HasValue(0); a TPH hierarchy where two sibling types reuse the same discriminator value; default discriminator values colliding after merging previously separate containers.
Common situations: Merging two containers whose types happened to share discriminator values; copy-paste of HasValue across IEntityTypeConfiguration classes; using a default like "Base" for several types; discriminator value collisions after a type rename that lost its custom value.
Related errors
- The entity type ' ' is sharing the container ' ' with other…
- The entity type ' ' is sharing the container ' ' with other…
- The partition key properties for entity type
- The partition key property
- An Azure Cosmos DB container name is defined on entity type
AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11).
Data as JSON: /api/errors/200b4a87da5bd01f.
Report an issue: GitHub.
Appendix: source
Thrown at src/EFCore.Cosmos/Infrastructure/Internal/CosmosModelValidator.cs:212
}
if (entityType.ClrType.IsInstantiable()
&& entityType.GetContainingPropertyName() == null)
{
if (entityType.FindDiscriminatorProperty() == null)
{
throw new InvalidOperationException(CosmosStrings.NoDiscriminatorProperty(entityType.DisplayName(), container));
}
var discriminatorValue = entityType.GetDiscriminatorValue();
if (discriminatorValue == null)
{
throw new InvalidOperationException(CosmosStrings.NoDiscriminatorValue(entityType.DisplayName(), container));
}
if (discriminatorValues.TryGetValue(discriminatorValue, out var duplicateEntityType))
{
throw new InvalidOperationException(
CosmosStrings.DuplicateDiscriminatorValue(
entityType.DisplayName(),
discriminatorValue,
duplicateEntityType.DisplayName(),
container));
}
discriminatorValues[discriminatorValue] = entityType;
var currentIsDiscriminatorMappingComplete = entityType.GetIsDiscriminatorMappingComplete();
if (isDiscriminatorMappingComplete == null)
{
isDiscriminatorMappingComplete = currentIsDiscriminatorMappingComplete;
}
else if (currentIsDiscriminatorMappingComplete != isDiscriminatorMappingComplete)
{
throw new InvalidOperationException(
CosmosStrings.IsDiscriminatorMappingCompleteMismatch(View on GitHub (pinned to 3a2006ef56)