diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 1cb6e28..81c5761 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,3 +1,7 @@
+#### 8.8.0 - April 21, 2026
+
+- Tests: Add `GenerativeInheritanceTests` — 5 tests for generative type inheritance: abstract base class, concrete derived classes, virtual method override dispatch verified at runtime
+
#### 8.7.0 - April 19, 2026
- Tests: Add `GenerativeMethodsTests` covering instance/static methods and method-count in generative types #505
diff --git a/tests/FSharp.TypeProviders.SDK.Tests.fsproj b/tests/FSharp.TypeProviders.SDK.Tests.fsproj
index 6856cde..9f39319 100644
--- a/tests/FSharp.TypeProviders.SDK.Tests.fsproj
+++ b/tests/FSharp.TypeProviders.SDK.Tests.fsproj
@@ -25,6 +25,7 @@
+
diff --git a/tests/GenerativeInheritanceTests.fs b/tests/GenerativeInheritanceTests.fs
new file mode 100644
index 0000000..ae6b402
--- /dev/null
+++ b/tests/GenerativeInheritanceTests.fs
@@ -0,0 +1,161 @@
+module TPSDK.GenerativeInheritanceTests
+
+// Tests for generative type inheritance: one ProvidedTypeDefinition deriving from
+// another, with virtual/abstract method dispatch verified at runtime.
+//
+// Scenario:
+// abstract class Animal { abstract Speak() : string }
+// class Dog(_name:string) extends Animal { override Speak() = "Woof! I am " + _name }
+// class Cat(_name:string) extends Animal { override Speak() = "Meow! I am " + _name }
+
+#nowarn "760" // IDisposable needs new
+
+open System
+open System.Reflection
+open Microsoft.FSharp.Core.CompilerServices
+open Microsoft.FSharp.Quotations
+open Xunit
+open ProviderImplementation.ProvidedTypes
+open ProviderImplementation.ProvidedTypesTesting
+open UncheckedQuotations
+
+[]
+type GenerativeInheritanceProvider (config: TypeProviderConfig) as this =
+ inherit TypeProviderForNamespaces (config)
+
+ let ns = "Inheritance.Provided"
+ let tempAssembly = ProvidedAssembly()
+ let container = ProvidedTypeDefinition(tempAssembly, ns, "Animals", Some typeof, isErased = false)
+
+ do
+ // Abstract base class: Animal
+ let animalType =
+ ProvidedTypeDefinition("Animal", Some typeof,
+ isErased = false, isAbstract = true, isSealed = false)
+
+ // Abstract method - no invokeCode; the TPSDK auto-applies Abstract|Virtual when class is abstract
+ let speakMethod = ProvidedMethod("Speak", [], typeof)
+ animalType.AddMember speakMethod
+ // Default constructor so derived classes can chain to it
+ animalType.AddMember (ProvidedConstructor([], invokeCode = fun _ -> <@@ () @@>))
+
+ // Concrete class: Dog
+ let dogType =
+ ProvidedTypeDefinition("Dog", Some (animalType :> Type),
+ isErased = false, isSealed = false)
+
+ let dogNameField = ProvidedField("_name", typeof)
+ dogType.AddMember dogNameField
+
+ dogType.AddMember
+ (ProvidedConstructor(
+ [ProvidedParameter("name", typeof)],
+ invokeCode = fun args ->
+ Expr.FieldSetUnchecked(args.[0], dogNameField, args.[1])))
+
+ let dogSpeak =
+ ProvidedMethod("Speak", [], typeof, isStatic = false,
+ invokeCode = fun args ->
+ let nameExpr = Expr.FieldGetUnchecked(args.[0], dogNameField)
+ <@@ "Woof! I am " + (%%nameExpr : string) @@>)
+ dogSpeak.AddMethodAttrs(MethodAttributes.Virtual ||| MethodAttributes.HideBySig)
+ dogType.AddMember dogSpeak
+ dogType.DefineMethodOverride(dogSpeak, speakMethod)
+
+ // Concrete class: Cat
+ let catType =
+ ProvidedTypeDefinition("Cat", Some (animalType :> Type),
+ isErased = false, isSealed = false)
+
+ let catNameField = ProvidedField("_name", typeof)
+ catType.AddMember catNameField
+
+ catType.AddMember
+ (ProvidedConstructor(
+ [ProvidedParameter("name", typeof)],
+ invokeCode = fun args ->
+ Expr.FieldSetUnchecked(args.[0], catNameField, args.[1])))
+
+ let catSpeak =
+ ProvidedMethod("Speak", [], typeof, isStatic = false,
+ invokeCode = fun args ->
+ let nameExpr = Expr.FieldGetUnchecked(args.[0], catNameField)
+ <@@ "Meow! I am " + (%%nameExpr : string) @@>)
+ catSpeak.AddMethodAttrs(MethodAttributes.Virtual ||| MethodAttributes.HideBySig)
+ catType.AddMember catSpeak
+ catType.DefineMethodOverride(catSpeak, speakMethod)
+
+ container.AddMembers [animalType; dogType; catType]
+ tempAssembly.AddTypes [container]
+ this.AddNamespace(ns, [container])
+
+let loadTestAssembly () =
+ let runtimeAssemblyRefs = Targets.DotNetStandard20FSharpRefs()
+ let runtimeAssembly = runtimeAssemblyRefs.[0]
+ let cfg = Testing.MakeSimulatedTypeProviderConfig(__SOURCE_DIRECTORY__, runtimeAssembly, runtimeAssemblyRefs)
+ let tp = GenerativeInheritanceProvider(cfg) :> TypeProviderForNamespaces
+ let providedType = tp.Namespaces.[0].GetTypes().[0]
+ let bytes = (tp :> ITypeProvider).GetGeneratedAssemblyContents(providedType.Assembly)
+ let assem = Assembly.Load bytes
+ assem.GetType("Inheritance.Provided.Animals")
+
+[]
+let ``Generative Dog type is a subclass of generative Animal type``() =
+ let animals = loadTestAssembly()
+ let animalType = animals.GetNestedType("Animal")
+ let dogType = animals.GetNestedType("Dog")
+ Assert.NotNull(animalType)
+ Assert.NotNull(dogType)
+ Assert.True(dogType.IsSubclassOf(animalType), "Dog should be a subclass of Animal")
+
+[]
+let ``Generative Animal Speak method is abstract``() =
+ let animals = loadTestAssembly()
+ let animalType = animals.GetNestedType("Animal")
+ let speakMethod = animalType.GetMethod("Speak", BindingFlags.Instance ||| BindingFlags.Public)
+ Assert.NotNull(speakMethod)
+ Assert.True(speakMethod.IsAbstract, "Animal.Speak should be abstract")
+ Assert.True(speakMethod.IsVirtual, "Animal.Speak should be virtual")
+
+[]
+let ``Generative Dog Speak method returns expected string``() =
+ let animals = loadTestAssembly()
+ let dogType = animals.GetNestedType("Dog")
+ Assert.NotNull(dogType)
+ let ctor = dogType.GetConstructor([| typeof |])
+ Assert.NotNull(ctor)
+ let dog = ctor.Invoke([| box "Buddy" |])
+ let speakMethod = dogType.GetMethod("Speak", BindingFlags.Instance ||| BindingFlags.Public)
+ Assert.NotNull(speakMethod)
+ let result = speakMethod.Invoke(dog, [||]) :?> string
+ Assert.Equal("Woof! I am Buddy", result)
+
+[]
+let ``Generative Cat Speak method returns expected string``() =
+ let animals = loadTestAssembly()
+ let catType = animals.GetNestedType("Cat")
+ Assert.NotNull(catType)
+ let ctor = catType.GetConstructor([| typeof |])
+ Assert.NotNull(ctor)
+ let cat = ctor.Invoke([| box "Whiskers" |])
+ let speakMethod = catType.GetMethod("Speak", BindingFlags.Instance ||| BindingFlags.Public)
+ let result = speakMethod.Invoke(cat, [||]) :?> string
+ Assert.Equal("Meow! I am Whiskers", result)
+
+[]
+let ``Generative Speak override is dispatched polymorphically via Animal base reference``() =
+ let animals = loadTestAssembly()
+ let animalType = animals.GetNestedType("Animal")
+ let dogType = animals.GetNestedType("Dog")
+ let catType = animals.GetNestedType("Cat")
+ let speakViaBase = animalType.GetMethod("Speak", BindingFlags.Instance ||| BindingFlags.Public)
+ Assert.NotNull(speakViaBase)
+
+ let dog = dogType.GetConstructor([| typeof |]).Invoke([| box "Rex" |])
+ let cat = catType.GetConstructor([| typeof |]).Invoke([| box "Luna" |])
+
+ // Invoke via the base-class MethodInfo — exercises virtual dispatch
+ let dogResult = speakViaBase.Invoke(dog, [||]) :?> string
+ let catResult = speakViaBase.Invoke(cat, [||]) :?> string
+ Assert.Equal("Woof! I am Rex", dogResult)
+ Assert.Equal("Meow! I am Luna", catResult)