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
- Pass only the supported IAnnotatable subtypes (IEntityType, IProperty, IKey, IForeignKey, INavigation, ISkipNavigation, IIndex, ICheckConstraint, ITrigger, ISequence, IModel, IComplexProperty, IRelationalPropertyOverrides).
- If you implemented a custom annotatable, override IAnnotationCodeGenerator to handle it instead of routing through the default switch.
- 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
- Type-check annotatables before routing to the generator.
- Override the provider's IAnnotationCodeGenerator for custom annotatable kinds.
- Keep EFCore.Design and provider versions aligned.
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
- A type-qualified method call requires an instance…
- Processing ' ' failed.
- The project language
- Anonymous type creation without members
- BinaryExpression with
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)