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

  1. Give every instantiable type in the shared container a distinct discriminator value (e.g. HasValue("order") vs HasValue("invoice")).
  2. Use a generator or convention that produces unique values (e.g. the entity's simple CLR type name) so manual edits cannot collide.
  3. If two types share a value intentionally because they are the same shape, merge them or map them via inheritance with a base value.
  4. 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

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


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)