dotnet/wpf · error · InvalidOperationException
SR.Format(SR.MustBaseOnStyleOfABaseType, _targetType.Name)
Error message
SR.Format(SR.MustBaseOnStyleOfABaseType, _targetType.Name)
What it means
During Seal(), if a Style declares BasedOn, the base style's TargetType must equal this style's DefaultTargetType or be an assignable-from (base of) this style's TargetType. A BasedOn style targeting an unrelated or derived-incompatible type violates the inheritance contract and throws InvalidOperationException.
Solutions
- Make the derived style's TargetType match the base style's TargetType (or a subtype of it).
- Choose a different base style whose TargetType is a base class of the current style's TargetType.
- Remove BasedOn and re-declare the needed setters if no type-compatible base exists.
Example fix
// before
var baseStyle = new Style(typeof(Button));
var derived = new Style(typeof(CheckBox)) { BasedOn = baseStyle }; // throws on Seal
// after
var baseStyle = new Style(typeof(ToggleButton));
var derived = new Style(typeof(CheckBox)) { BasedOn = baseStyle }; Defensive patterns
Strategy: validation
Validate before calling
if (baseStyle != null && derived.TargetType != null &&
baseStyle.TargetType != derived.TargetType &&
!baseStyle.TargetType.IsAssignableFrom(derived.TargetType))
throw new InvalidOperationException("BasedOn style targets an incompatible type."); Type guard
static bool BasedOnCompatible(Style derived, Style baseStyle) => baseStyle == null || baseStyle.TargetType == derived.TargetType || baseStyle.TargetType.IsAssignableFrom(derived.TargetType);
Try / catch
try { derived.Seal(); }
catch (InvalidOperationException ex) { log.Error("BasedOn TargetType incompatible", ex); } Prevention
- Derive styles only from styles whose TargetType is the same or a base type.
- Use a common base-type style (e.g. typeof(Control)) for shared BasedOn chains.
- Verify StaticResource keys in BasedOn resolve to the intended type.
When it happens
Trigger: style.BasedOn = otherStyle where otherStyle.TargetType is neither the same type nor a base type of this style's TargetType (e.g. a CheckBox style based on a Button style).
Common situations: Refactoring control types without updating BasedOn chains; merging resource dictionaries where a style key now points to a style with a different TargetType; typos in {StaticResource} keys resolving to a similarly-named style of another type.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- SR.Format(SR.StyleBasedOnHasLoop)
- SR.Format(SR.CannotChangeAfterSealed, "EventTrigger")
- SR.Format(SR.CannotChangeAfterSealed, "SetterBase")
- SR.Format(SR.CannotChangeAfterSealed…
- SR.Format(SR.CannotChangeAfterSealed, "Style")
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/016b1b42c20229d1.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Style.cs:501
// 99% case - Style is already sealed.
if (_sealed)
{
return;
}
// Most parameter checking is done as "upstream" as possible, but some
// can't be checked until Style is sealed.
if (_targetType == null)
{
throw new InvalidOperationException(SR.Format(SR.NullPropertyIllegal, "TargetType"));
}
if (_basedOn != null)
{
if(DefaultTargetType != _basedOn.TargetType &&
!_basedOn.TargetType.IsAssignableFrom(_targetType))
{
throw new InvalidOperationException(SR.Format(SR.MustBaseOnStyleOfABaseType, _targetType.Name));
}
}
// Seal setters
_setters?.Seal();
// Seal triggers
_visualTriggers?.Seal();
// Will throw InvalidOperationException if we find a loop of
// BasedOn references. (A.BasedOn = B, B.BasedOn = C, C.BasedOn = A)
CheckForCircularBasedOnReferences();
// Seal BasedOn Style chain
_basedOn?.Seal();
// Seal the ResourceDictionary
_resources?.IsReadOnly = true;View on GitHub (pinned to 81131a70a4)