dotnet/efcore · error · ArgumentException

Unhandled annotatable type

Error message

Unhandled annotatable type '{annotatableType}'.

What it means

Thrown by IAnnotationCodeGenerator.RemoveAnnotationsHandledByConventions when an IAnnotatable passed to it is not one of the recognized subtypes (entity type, property, complex property, key, foreign key, navigation, skip navigation, index, check constraint, trigger, sequence, model, relational overrides). It is a design-time ArgumentException used to surface unsupported annotation targets during scaffolding/migrations code generation.

Solutions

  1. Pass only the supported IAnnotatable subtypes (IEntityType, IProperty, IKey, IForeignKey, INavigation, ISkipNavigation, IIndex, ICheckConstraint, ITrigger, ISequence, IModel, IComplexProperty, IRelationalPropertyOverrides).
  2. If you implemented a custom annotatable, override IAnnotationCodeGenerator to handle it instead of routing through the default switch.
  3. Ensure the EF Core design-time package versions match the runtime provider versions.

Example fix

// before: passing a custom annotatable to the generator
codegen.RemoveAnnotationsHandledByConventions(myCustomAnnotatable, annotations); // throws

// after: handle known types; branch custom types yourself
if (myCustomAnnotatable is IProperty prop)
{
    codegen.RemoveAnnotationsHandledByConventions(prop, annotations);
}
else
{
    // custom handling for myCustomAnnotatable
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Only call the convention-removal API for supported annotatable types
static readonly HashSet<Type> Supported = new()
{
    typeof(IModel), typeof(IEntityType), typeof(IProperty), typeof(IComplexProperty),
    typeof(IRelationalPropertyOverrides), typeof(IKey), typeof(IForeignKey),
    typeof(INavigation), typeof(ISkipNavigation), typeof(IIndex),
    typeof(ICheckConstraint), typeof(ITrigger), typeof(ISequence)
};
if (Supported.Contains(annotatable.GetType()))
    generator.RemoveAnnotationsHandledByConventions(annotatable, annotations);

Type guard

static bool IsSupportedAnnotatable(IAnnotatable a)
    => a is IModel or IEntityType or IProperty or IComplexProperty
       or IRelationalPropertyOverrides or IKey or IForeignKey
       or INavigation or ISkipNavigation or IIndex
       or ICheckConstraint or ITrigger or ISequence;

Prevention

When it happens

Trigger: A design-time pipeline (scaffolding, migrations design, or a custom IAnnotationCodeGenerator) passes an IAnnotatable implementation that the default switch does not handle — e.g. a custom annotatable type or a newly added EF annotatable not yet covered.

Common situations: Extending EF Core with custom metadata objects that implement IAnnotatable; using a provider/extension whose annotatables are not in the recognized set; EF version mismatch where a newer annotatable type reaches an older generator.

Related errors


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

Appendix: source

Thrown at src/EFCore.Relational/Design/IAnnotationCodeGenerator.cs:258

            case IIndex index:
                RemoveAnnotationsHandledByConventions(index, annotations);
                return;

            case ITrigger trigger:
                RemoveAnnotationsHandledByConventions(trigger, annotations);
                return;

            case IRelationalPropertyOverrides overrides:
                RemoveAnnotationsHandledByConventions(overrides, annotations);
                return;

            case ISequence sequence:
                RemoveAnnotationsHandledByConventions(sequence, annotations);
                return;

            default:
                throw new ArgumentException(RelationalStrings.UnhandledAnnotatableType(annotatable.GetType()));
        }
    }

    /// <summary>
    ///     For the given annotations which have corresponding fluent API calls, returns those fluent API calls
    ///     and removes the annotations.
    /// </summary>
    /// <param name="model">The model to which the annotations are applied.</param>
    /// <param name="annotations">The set of annotations from which to generate fluent API calls.</param>
    IReadOnlyList<MethodCallCodeFragment> GenerateFluentApiCalls(
        IModel model,
        IDictionary<string, IAnnotation> annotations)
        => [];

    /// <summary>
    ///     For the given annotations which have corresponding fluent API calls, returns those fluent API calls
    ///     and removes the annotations.
    /// </summary>

View on GitHub (pinned to 3a2006ef56)