diff --git a/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Custom/CustomType.cs b/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Custom/CustomType.cs
index 95ee34ab4504b6..56ab55515ce194 100644
--- a/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Custom/CustomType.cs
+++ b/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Custom/CustomType.cs
@@ -44,6 +44,7 @@ public override bool IsInstanceOfType([NotNullWhen(true)] object? o)
             return IsAssignableFrom(objectType);
         }
 
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
         public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
         {
             // list of properties on this type according to the underlying ReflectionContext
@@ -139,6 +140,7 @@ public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
             return binder.SelectProperty(bindingAttr, matchingProperties.ToArray(), returnType, types, modifiers);
         }
 
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
         public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
         {
             // list of methods on this type according to the underlying ReflectionContext
diff --git a/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Delegation/DelegatingType.cs b/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Delegation/DelegatingType.cs
index bd7ef3ff90eaeb..5bad1592b9ba49 100644
--- a/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Delegation/DelegatingType.cs
+++ b/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Delegation/DelegatingType.cs
@@ -325,11 +325,17 @@ public override EventInfo[] GetEvents(BindingFlags bindingAttr)
             return _typeInfo.GetEvents(bindingAttr);
         }
 
+#if NET8_0_OR_GREATER
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
+#endif
         public override FieldInfo? GetField(string name, BindingFlags bindingAttr)
         {
             return _typeInfo.GetField(name, bindingAttr);
         }
 
+#if NET8_0_OR_GREATER
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
+#endif
         public override FieldInfo[] GetFields(BindingFlags bindingAttr)
         {
             return _typeInfo.GetFields(bindingAttr);
@@ -345,6 +351,14 @@ public override Type[] GetInterfaces()
             return _typeInfo.GetInterfaces();
         }
 
+#if NET8_0_OR_GREATER
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
+            DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
+            DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
+            DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
+            DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
+            DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
+#endif
         public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
         {
             return _typeInfo.GetMembers(bindingAttr);
@@ -358,6 +372,9 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
                 _typeInfo.GetMethod(name, bindingAttr, binder, callConvention, types, modifiers);
         }
 
+#if NET8_0_OR_GREATER
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
+#endif
         public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
         {
             return _typeInfo.GetMethods(bindingAttr);
@@ -373,6 +390,9 @@ public override Type[] GetNestedTypes(BindingFlags bindingAttr)
             return _typeInfo.GetNestedTypes(bindingAttr);
         }
 
+#if NET8_0_OR_GREATER
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
+#endif
         public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
         {
             return _typeInfo.GetProperties(bindingAttr);
diff --git a/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Projection/ProjectingType.cs b/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Projection/ProjectingType.cs
index 0ac9bb0de89f38..f61ea789bd7386 100644
--- a/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Projection/ProjectingType.cs
+++ b/src/libraries/System.Reflection.Context/src/System/Reflection/Context/Projection/ProjectingType.cs
@@ -206,11 +206,13 @@ public override EventInfo[] GetEvents(BindingFlags bindingAttr)
             return _projector.Project(base.GetEvents(bindingAttr), _projector.ProjectEvent);
         }
 
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
         public override FieldInfo? GetField(string name, BindingFlags bindingAttr)
         {
             return _projector.ProjectField(base.GetField(name, bindingAttr));
         }
 
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
         public override FieldInfo[] GetFields(BindingFlags bindingAttr)
         {
             return _projector.Project(base.GetFields(bindingAttr), _projector.ProjectField);
@@ -226,6 +228,12 @@ public override Type[] GetInterfaces()
             return _projector.Project(base.GetInterfaces(), _projector.ProjectType);
         }
 
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields |
+            DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods |
+            DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents |
+            DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties |
+            DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors |
+            DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
         public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
         {
             MethodInfo[] methods = GetMethods(bindingAttr);
@@ -264,6 +272,7 @@ public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
             return _projector.ProjectMethod(base.GetMethodImpl(name, bindingAttr, binder, callConvention, types, modifiers));
         }
 
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
         public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
         {
             return _projector.Project(base.GetMethods(bindingAttr), _projector.ProjectMethod);
@@ -279,6 +288,7 @@ public override Type[] GetNestedTypes(BindingFlags bindingAttr)
             return _projector.Project(base.GetNestedTypes(bindingAttr), _projector.ProjectType);
         }
 
+        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
         public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
         {
             return _projector.Project(base.GetProperties(bindingAttr), _projector.ProjectProperty);
diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs
index 32fd98cbe039ca..713e1d2dcace59 100644
--- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs
+++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs
@@ -36,7 +36,6 @@
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Reflection.Runtime.TypeParsing;
-using System.Runtime.CompilerServices;
 using System.Text.RegularExpressions;
 using ILLink.Shared;
 using ILLink.Shared.TrimAnalysis;
@@ -779,45 +778,6 @@ void MarkMethodIfNeededByBaseMethod (MethodDefinition method)
 			}
 		}
 
-		/// 
-		/// Returns true if  implements  and the interface implementation is marked,
-		/// or if any marked interface implementations on  are interfaces that implement  and that interface implementation is marked
-		/// 
-		bool IsInterfaceImplementationMarkedRecursively (TypeDefinition type, TypeDefinition interfaceType)
-		{
-			if (type.HasInterfaces) {
-				foreach (var intf in type.Interfaces) {
-					TypeDefinition? resolvedInterface = Context.Resolve (intf.InterfaceType);
-					if (resolvedInterface == null)
-						continue;
-
-					if (Annotations.IsMarked (intf) && RequiresInterfaceRecursively (resolvedInterface, interfaceType))
-						return true;
-				}
-			}
-
-			return false;
-		}
-
-		bool RequiresInterfaceRecursively (TypeDefinition typeToExamine, TypeDefinition interfaceType)
-		{
-			if (typeToExamine == interfaceType)
-				return true;
-
-			if (typeToExamine.HasInterfaces) {
-				foreach (var iface in typeToExamine.Interfaces) {
-					var resolved = Context.TryResolve (iface.InterfaceType);
-					if (resolved == null)
-						continue;
-
-					if (RequiresInterfaceRecursively (resolved, interfaceType))
-						return true;
-				}
-			}
-
-			return false;
-		}
-
 		void ProcessDefaultImplementation (OverrideInformation ov)
 		{
 			Debug.Assert (ov.IsOverrideOfInterfaceMember);
@@ -825,7 +785,9 @@ void ProcessDefaultImplementation (OverrideInformation ov)
 				|| ov.Override.IsStatic && !Annotations.IsRelevantToVariantCasting (ov.InterfaceImplementor.Implementor))
 				return;
 
-			MarkInterfaceImplementation (ov.InterfaceImplementor.InterfaceImplementation);
+			foreach (var ifaceImpl in ov.InterfaceImplementor.MostDirectInterfaceImplementationPath) {
+				MarkInterfaceImplementation (ifaceImpl);
+			}
 		}
 
 		void MarkMarshalSpec (IMarshalInfoProvider spec, in DependencyInfo reason)
@@ -2450,37 +2412,35 @@ void MarkNamedProperty (TypeDefinition type, string property_name, in Dependency
 
 		void MarkInterfaceImplementations (TypeDefinition type)
 		{
-			if (!type.HasInterfaces)
-				return;
-
-			foreach (var iface in type.Interfaces) {
-				// Only mark interface implementations of interface types that have been marked.
-				// This enables stripping of interfaces that are never used
-				if (ShouldMarkInterfaceImplementation (type, iface))
-					MarkInterfaceImplementation (iface, new MessageOrigin (type));
+			foreach (var interfaceImplementor in Annotations.GetRecursiveInterfaces (type)) {
+				if (ShouldMarkInterfaceImplementation (interfaceImplementor)) {
+					foreach (InterfaceImplementation interfaceImpl in interfaceImplementor.MostDirectInterfaceImplementationPath) {
+						MarkInterfaceImplementation (interfaceImpl, new MessageOrigin (type));
+					}
+				}
 			}
 		}
 
-		protected virtual bool ShouldMarkInterfaceImplementation (TypeDefinition type, InterfaceImplementation iface)
+		protected virtual bool ShouldMarkInterfaceImplementation (InterfaceImplementor interfaceImplementor)
 		{
-			if (Annotations.IsMarked (iface))
+			if (interfaceImplementor.IsMostDirectImplementationMarked (Annotations))
 				return false;
 
-			if (!Context.IsOptimizationEnabled (CodeOptimizations.UnusedInterfaces, type))
+			if (!Context.IsOptimizationEnabled (CodeOptimizations.UnusedInterfaces, interfaceImplementor.Implementor))
 				return true;
 
-			if (Context.Resolve (iface.InterfaceType) is not TypeDefinition resolvedInterfaceType)
+			if (interfaceImplementor.InterfaceType is null)
 				return false;
 
-			if (Annotations.IsMarked (resolvedInterfaceType))
+			if (Annotations.IsMarked (interfaceImplementor.InterfaceType))
 				return true;
 
 			// It's hard to know if a com or windows runtime interface will be needed from managed code alone,
 			// so as a precaution we will mark these interfaces once the type is instantiated
-			if (resolvedInterfaceType.IsImport || resolvedInterfaceType.IsWindowsRuntime)
+			if (interfaceImplementor.InterfaceType.IsImport || interfaceImplementor.InterfaceType.IsWindowsRuntime)
 				return true;
 
-			return IsFullyPreserved (type);
+			return IsFullyPreserved (interfaceImplementor.Implementor);
 		}
 
 		void MarkGenericParameterProvider (IGenericParameterProvider provider)
@@ -2560,12 +2520,10 @@ bool IsInterfaceImplementationMethodNeededByTypeDueToInterface (OverrideInformat
 			if (Annotations.IsMarked (method))
 				return false;
 
-			// If the interface implementation is not marked, do not mark the implementation method
-			// A type that doesn't implement the interface isn't required to have methods that implement the interface.
-			InterfaceImplementation? iface = overrideInformation.InterfaceImplementor.InterfaceImplementation;
-			if (!((iface is not null && Annotations.IsMarked (iface))
-				|| IsInterfaceImplementationMarkedRecursively (method.DeclaringType, @base.DeclaringType)))
+			// If there is no chain of interface implementations that make the type implement the interface, the method isn't required
+			if (!overrideInformation.InterfaceImplementor.IsMarked(Annotations)) {
 				return false;
+			}
 
 			// If the interface method is not marked and the interface doesn't come from a preserved scope, do not mark the implementation method
 			// Unmarked interface methods from link assemblies will be removed so the implementing method does not need to be kept.
diff --git a/src/tools/illink/src/linker/Linker/Annotations.cs b/src/tools/illink/src/linker/Linker/Annotations.cs
index a7b3198265e812..6a21a921e76f9c 100644
--- a/src/tools/illink/src/linker/Linker/Annotations.cs
+++ b/src/tools/illink/src/linker/Linker/Annotations.cs
@@ -31,6 +31,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.Collections.Immutable;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
@@ -717,5 +718,7 @@ public void EnqueueVirtualMethod (MethodDefinition method)
 			if (FlowAnnotations.RequiresVirtualMethodDataFlowAnalysis (method) || HasLinkerAttribute (method))
 				VirtualMethodsWithAnnotationsToValidate.Add (method);
 		}
+
+		internal ImmutableArray GetRecursiveInterfaces (TypeDefinition type) => TypeMapInfo.GetRecursiveInterfaces (type);
 	}
 }
diff --git a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs
index e981ce872703f7..321584cb74e276 100644
--- a/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs
+++ b/src/tools/illink/src/linker/Linker/InterfaceImplementor.cs
@@ -2,9 +2,9 @@
 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
 
 using System;
-using System.Collections;
-using System.Collections.Generic;
+using System.Collections.Immutable;
 using System.Diagnostics;
+using System.Linq;
 using Mono.Cecil;
 
 namespace Mono.Linker
@@ -15,45 +15,164 @@ public class InterfaceImplementor
 		/// The type that implements .
 		/// 
 		public TypeDefinition Implementor { get; }
+
 		/// 
-		/// The .interfaceimpl on that points to 
+		/// The type of the interface that is implemented by 
+		/// Null if the type could not be resolved
 		/// 
-		public InterfaceImplementation InterfaceImplementation { get; }
+		public TypeDefinition? InterfaceType { get; }
+
 		/// 
-		/// The type of the interface that is implemented by 
+		/// A  to the  with the generic parameters substituted.
 		/// 
-		public TypeDefinition InterfaceType { get; }
+		public TypeReference InflatedInterface { get; }
 
-		public InterfaceImplementor (TypeDefinition implementor, InterfaceImplementation interfaceImplementation, TypeDefinition interfaceType, IMetadataResolver resolver)
+		/// 
+		/// The graphs of s that make  implement the .
+		/// There can be many ways a type implements an interface if an explicit interface implementation is given for an interface that is also implemented recursively due to another interface implementation.
+		/// It will be in the following order:
+		///  1. Explicit interface implementation on 
+		///  2. Explicit interface implementation on a base type of 
+		///  3. Recursive interface implementations on an explicitly implemented interface on  or it's base types
+		/// 
+		public readonly ImmutableArray InterfaceImplementationNodes;
+
+		public bool HasExplicitImplementation => InterfaceImplementationNodes[0].Length == 0;
+
+		public InterfaceImplementor (TypeDefinition implementor, TypeDefinition? interfaceType, TypeReference inflatedInterface, ImmutableArray implNode, LinkContext context)
 		{
 			Implementor = implementor;
-			InterfaceImplementation = interfaceImplementation;
 			InterfaceType = interfaceType;
-			Debug.Assert(resolver.Resolve (interfaceImplementation.InterfaceType) == interfaceType);
+			InterfaceImplementationNodes = implNode;
+			InflatedInterface = inflatedInterface;
+			Debug.Assert (context.Resolve (inflatedInterface) == interfaceType);
+			Debug.Assert (implNode.Length != 0);
+			Debug.Assert (implNode.All (i => interfaceType == context.Resolve (i.GetLast ().InterfaceType)));
+		}
+
+		/// 
+		/// An Enumerable over the most direct  chain to the 
+		/// 
+		public ShortestInterfaceImplementationChainEnumerator MostDirectInterfaceImplementationPath => new (this);
+
+		public struct ShortestInterfaceImplementationChainEnumerator
+		{
+			InterfaceImplementationNode _current;
+			bool _hasMoved;
+			public ShortestInterfaceImplementationChainEnumerator (InterfaceImplementor implementor)
+			{
+				_current = implementor.InterfaceImplementationNodes[0];
+				_hasMoved = false;
+			}
+			public ShortestInterfaceImplementationChainEnumerator GetEnumerator () => this;
+			public InterfaceImplementation Current => _current.InterfaceImplementation;
+
+			public bool MoveNext ()
+			{
+				if (!_hasMoved) {
+					_hasMoved = true;
+					return true;
+				}
+				if (_current.Next.Length == 0)
+					return false;
+				_current = _current.Next[0];
+				return true;
+			}
+		}
+
+		/// 
+		/// Returns true if the most direct implementation of  is marked.  may still have a different recursive implementation marked.
+		/// 
+		public bool IsMostDirectImplementationMarked (AnnotationStore annotations)
+		{
+			return InterfaceImplementationNodes[0].IsMostDirectImplementationMarked (annotations);
 		}
 
-		public static InterfaceImplementor Create(TypeDefinition implementor, TypeDefinition interfaceType, IMetadataResolver resolver)
+		/// 
+		/// Returns true if  implements  via any of the possible interface implementation chains.
+		/// 
+		public bool IsMarked (AnnotationStore annotations)
 		{
-			foreach(InterfaceImplementation iface in implementor.Interfaces) {
-				if (resolver.Resolve(iface.InterfaceType) == interfaceType) {
-					return new InterfaceImplementor(implementor, iface, interfaceType, resolver);
+			foreach (var i in InterfaceImplementationNodes) {
+				if (i.IsMarked (annotations))
+					return true;
+			}
+			return false;
+		}
+
+		/// 
+		/// Represents a node in the graph of a type implementing an interface.
+		/// 
+		public sealed class InterfaceImplementationNode
+		{
+			/// 
+			/// The  that is on  that is part of the chain of interface implementations.
+			/// 
+			public InterfaceImplementation InterfaceImplementation { get; }
+
+			/// 
+			/// The type that has  in its .
+			/// 
+			public TypeDefinition InterfaceImplementationProvider { get; }
+
+			/// 
+			/// The s that are on the type pointed to by  that lead to the interface type.
+			/// 
+			public ImmutableArray Next { get; }
+
+			/// 
+			/// The number of interface implementations on the most direct way the interface is implemented from 
+			/// 
+			public int Length {
+				get {
+					if (_length != -1)
+						return _length;
+					if (Next.Length == 0)
+						return _length = 0;
+					return _length = Next[0].Length + 1;
 				}
 			}
+			int _length = -1;
+
+			public InterfaceImplementationNode (InterfaceImplementation interfaceImplementation, TypeDefinition interfaceImplementationProvider, ImmutableArray next)
+			{
+				InterfaceImplementation = interfaceImplementation;
+				InterfaceImplementationProvider = interfaceImplementationProvider;
+				Next = next;
+			}
+
+			public bool IsMostDirectImplementationMarked (AnnotationStore annotations)
+			{
+				if (!annotations.IsMarked (InterfaceImplementation))
+					return false;
+				if (Next.Length == 0)
+					return true;
+				return Next[0].IsMostDirectImplementationMarked (annotations);
+			}
+
+			public bool IsMarked (AnnotationStore annotations)
+			{
+				if (!annotations.IsMarked (InterfaceImplementation))
+					return false;
+
+				if (Next.Length == 0)
+					return true;
 
-			Queue ifacesToCheck = new ();
-			ifacesToCheck.Enqueue(implementor);
-			while (ifacesToCheck.Count > 0) {
-				var currentIface = ifacesToCheck.Dequeue ();
+				foreach (var impl in Next) {
+					if (impl.IsMarked (annotations))
+						return true;
+				}
+				return false;
+			}
 
-				foreach(InterfaceImplementation ifaceImpl in currentIface.Interfaces) {
-					var iface = resolver.Resolve (ifaceImpl.InterfaceType);
-					if (iface == interfaceType) {
-						return new InterfaceImplementor(implementor, ifaceImpl, interfaceType, resolver);
-					}
-					ifacesToCheck.Enqueue (iface);
+			public InterfaceImplementation GetLast ()
+			{
+				var curr = this;
+				while (curr.Next.Length > 0) {
+					curr = curr.Next[0];
 				}
+				return curr.InterfaceImplementation;
 			}
-			throw new InvalidOperationException ($"Type '{implementor.FullName}' does not implement interface '{interfaceType.FullName}' directly or through any interfaces");
 		}
 	}
 }
diff --git a/src/tools/illink/src/linker/Linker/OverrideInformation.cs b/src/tools/illink/src/linker/Linker/OverrideInformation.cs
index 0727d5d25c19a0..c306a3c111eb1b 100644
--- a/src/tools/illink/src/linker/Linker/OverrideInformation.cs
+++ b/src/tools/illink/src/linker/Linker/OverrideInformation.cs
@@ -10,10 +10,20 @@ namespace Mono.Linker
 	[DebuggerDisplay ("{Override}")]
 	public class OverrideInformation
 	{
+		/// 
+		/// The method that is being overridden or implemented
+		/// 
 		public MethodDefinition Base { get; }
 
+		/// 
+		/// The method that overrides . For interface methods, this may be a method on a base type, or a default interface method.
+		/// 
 		public MethodDefinition Override { get; }
 
+		/// 
+		/// For overrides of interface methods, includes info about the interface / implementor pair that correspong to the base / override pair
+		/// The  may be a method on , one of it's base types, or a default interface method on one of the interfaces implemented by it.
+		/// 
 		internal InterfaceImplementor? InterfaceImplementor { get; }
 
 		internal OverrideInformation (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null)
@@ -22,14 +32,23 @@ internal OverrideInformation (MethodDefinition @base, MethodDefinition @override
 			Override = @override;
 			InterfaceImplementor = interfaceImplementor;
 			// Ensure we have an interface implementation if the base method is from an interface and the override method is on a class
-			Debug.Assert(@base.DeclaringType.IsInterface && interfaceImplementor != null
+			Debug.Assert (@base.DeclaringType.IsInterface && interfaceImplementor != null
 						|| !@base.DeclaringType.IsInterface && interfaceImplementor == null);
 			// Ensure the interfaceImplementor is for the interface we expect
 			Debug.Assert (@base.DeclaringType.IsInterface ? interfaceImplementor!.InterfaceType == @base.DeclaringType : true);
 		}
 
-		public InterfaceImplementation? MatchingInterfaceImplementation
-			=> InterfaceImplementor?.InterfaceImplementation;
+		public InterfaceImplementation? MatchingInterfaceImplementation {
+			get {
+				if (InterfaceImplementor is null)
+					return null;
+				InterfaceImplementation? last = null;
+				foreach (InterfaceImplementation curr in InterfaceImplementor!.MostDirectInterfaceImplementationPath) {
+					last = curr;
+				}
+				return last;
+			}
+		}
 
 		public TypeDefinition? InterfaceType
 			=> InterfaceImplementor?.InterfaceType;
diff --git a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs
index 7e68b71bcb7d08..a5304569192be6 100644
--- a/src/tools/illink/src/linker/Linker/TypeMapInfo.cs
+++ b/src/tools/illink/src/linker/Linker/TypeMapInfo.cs
@@ -29,16 +29,16 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.Collections.Generic;
+using System.Collections.Immutable;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using Mono.Cecil;
+using static Mono.Linker.InterfaceImplementor;
 
 namespace Mono.Linker
 {
-
 	public class TypeMapInfo
 	{
 		readonly HashSet assemblies = new HashSet ();
@@ -46,6 +46,7 @@ public class TypeMapInfo
 		protected readonly Dictionary> base_methods = new Dictionary> ();
 		protected readonly Dictionary> override_methods = new Dictionary> ();
 		protected readonly Dictionary> default_interface_implementations = new Dictionary> ();
+		readonly Dictionary> _interfaces = new ();
 
 		public TypeMapInfo (LinkContext context)
 		{
@@ -87,6 +88,18 @@ public void EnsureProcessed (AssemblyDefinition assembly)
 			return bases;
 		}
 
+		InterfaceImplementor? GetInterfaceImplementor (TypeDefinition implementor, TypeDefinition interfaceType)
+		{
+			if (!_interfaces.TryGetValue (implementor, out var implrs))
+				return null;
+
+			foreach (var iface in implrs) {
+				if (iface.InterfaceType == interfaceType)
+					return iface;
+			}
+			return null;
+		}
+
 		/// 
 		/// Returns a list of all default interface methods that implement  for a type.
 		/// ImplementingType is the type that implements the interface,
@@ -96,28 +109,38 @@ public void EnsureProcessed (AssemblyDefinition assembly)
 		/// The interface method to find default implementations for
 		public IEnumerable? GetDefaultInterfaceImplementations (MethodDefinition baseMethod)
 		{
+			EnsureProcessed (baseMethod.Module.Assembly);
 			default_interface_implementations.TryGetValue (baseMethod, out var ret);
 			return ret;
 		}
 
-		public void AddBaseMethod (MethodDefinition method, MethodDefinition @base, InterfaceImplementor? interfaceImplementor)
+		internal ImmutableArray GetRecursiveInterfaces (TypeDefinition type)
+		{
+			EnsureProcessed (type.Module.Assembly);
+			return _interfaces.TryGetValue (type, out var value) ? value : [];
+		}
+
+		void AddBaseMethod (MethodDefinition method, OverrideInformation overrideInformation)
 		{
-			base_methods.AddToList (method, new OverrideInformation (@base, method, interfaceImplementor));
+			Debug.Assert (overrideInformation.Override == method);
+			base_methods.AddToList (method, overrideInformation);
 		}
 
-		public void AddOverride (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null)
+		void AddOverrideOfMethod (MethodDefinition @base, OverrideInformation overrideInformation)
 		{
-			override_methods.AddToList (@base, new OverrideInformation (@base, @override, interfaceImplementor));
+			Debug.Assert (overrideInformation.Base == @base);
+			override_methods.AddToList (@base, overrideInformation);
 		}
 
-		public void AddDefaultInterfaceImplementation (MethodDefinition @base, InterfaceImplementor interfaceImplementor, MethodDefinition defaultImplementationMethod)
+		void AddDefaultInterfaceImplementation (MethodDefinition @base, InterfaceImplementor interfaceImplementor, MethodDefinition defaultImplementationMethod)
 		{
-			Debug.Assert(@base.DeclaringType.IsInterface);
+			Debug.Assert (@base.DeclaringType.IsInterface);
 			default_interface_implementations.AddToList (@base, new OverrideInformation (@base, defaultImplementationMethod, interfaceImplementor));
 		}
 
-		protected virtual void MapType (TypeDefinition type)
+		void MapType (TypeDefinition type)
 		{
+			MapInterfacesOnType (type);
 			MapVirtualMethods (type);
 			MapInterfaceMethodsInTypeHierarchy (type);
 
@@ -128,6 +151,109 @@ protected virtual void MapType (TypeDefinition type)
 				MapType (nested);
 		}
 
+		void MapInterfacesOnType (TypeDefinition type)
+		{
+			if (_interfaces.ContainsKey (type))
+				return;
+
+			// Map from inflated interface type => list of every way to recursively implement that interface in 'type declaration order' according to ECMA 335 12.2
+			Dictionary> waysToImplementIface = new (InflatedInterfaceComparer);
+
+			// Get all explicit interfaces of this type
+			foreach (var directIface in type.Interfaces) {
+				InterfaceImplementationNode directlyImplementedNode = new InterfaceImplementationNode (directIface, type, []);
+				TypeReference inflatedDirectIface = directIface.InterfaceType.TryInflateFrom (type, context)!;
+				waysToImplementIface.AddToList (inflatedDirectIface, directlyImplementedNode);
+			}
+
+			// Add interfaces on base type
+			if (type.BaseType is { } baseType && context.Resolve (baseType) is { } baseDef) {
+				MapInterfacesOnType (baseDef);
+				var baseInterfaces = _interfaces[baseDef];
+				foreach (var item in baseInterfaces) {
+					var inflatedInterface = item.InflatedInterface.TryInflateFrom (type.BaseType, context);
+					Debug.Assert (inflatedInterface is not null);
+					foreach (var node in item.InterfaceImplementationNodes) {
+						waysToImplementIface.AddToList (inflatedInterface, node);
+					}
+				}
+			}
+
+			// Recursive interfaces next to preserve Inherit/Implement tree order
+			foreach (var directIface in type.Interfaces) {
+				// If we can't resolve the interface type we can't find recursive interfaces
+				var ifaceDirectlyOnType = context.Resolve (directIface.InterfaceType);
+				if (ifaceDirectlyOnType is null) {
+					continue;
+				}
+				MapInterfacesOnType (ifaceDirectlyOnType);
+				TypeReference inflatedDirectIface = directIface.InterfaceType.TryInflateFrom (type, context)!;
+				var recursiveInterfaces = _interfaces[ifaceDirectlyOnType];
+				foreach (var recursiveInterface in recursiveInterfaces) {
+					var implToRecursiveIfaceChain = new InterfaceImplementationNode (directIface, type, recursiveInterface.InterfaceImplementationNodes);
+					// Inflate the generic arguments up to the terminal interfaceImpl to get the inflated interface type implemented by this type
+					TypeReference inflatedRecursiveInterface = inflatedDirectIface;
+					foreach (var interfaceImpl in recursiveInterface.MostDirectInterfaceImplementationPath) {
+						inflatedRecursiveInterface = interfaceImpl.InterfaceType.TryInflateFrom (inflatedRecursiveInterface, context)!;
+					}
+					waysToImplementIface.AddToList (inflatedRecursiveInterface, implToRecursiveIfaceChain);
+				}
+			}
+			ImmutableArray.Builder builder = ImmutableArray.CreateBuilder (waysToImplementIface.Count);
+			foreach (var kvp in waysToImplementIface) {
+				builder.Add (new InterfaceImplementor (type, context.Resolve (kvp.Key), kvp.Key, kvp.Value.ToImmutableArray (), context));
+			}
+			_interfaces.Add (type, builder.MoveToImmutable ());
+		}
+
+		/// 
+		/// Used only to compare inflated interfaces in MapInterfacesOnType
+		/// 
+		EqualityComparer InflatedInterfaceComparer => _inflatedInterfaceComparer ??= EqualityComparer.Create (InterfaceTypeEquals, t => context.Resolve (t)?.GetHashCode () ?? 0);
+		EqualityComparer? _inflatedInterfaceComparer;
+
+		/// 
+		/// Compares two TypeReferences to interface types and determines if they are equivalent references, taking into account generic arguments and element types.
+		/// 
+		bool InterfaceTypeEquals (TypeReference? type, TypeReference? other)
+		{
+			Debug.Assert (type is not null && other is not null);
+			Debug.Assert (context.TryResolve (type)?.IsInterface is null or true);
+			Debug.Assert (context.TryResolve (other)?.IsInterface is null or true);
+			return TypeEquals (type, other);
+
+			bool TypeEquals (TypeReference type1, TypeReference type2)
+			{
+				if (type1 == type2)
+					return true;
+
+				if (context.TryResolve (type1) != context.TryResolve (type2))
+					return false;
+
+				if (type1 is GenericInstanceType genericInstance1) {
+					if (type2 is not GenericInstanceType genericInstance2)
+						return false;
+					if (genericInstance1.HasGenericParameters != genericInstance2.HasGenericParameters)
+						return false;
+					if (genericInstance1.GenericParameters.Count != genericInstance2.GenericParameters.Count
+						|| genericInstance2.GenericArguments.Count != genericInstance2.GenericArguments.Count)
+						return false;
+					for (var i = 0; i < genericInstance1.GenericArguments.Count; ++i) {
+						if (!TypeEquals (genericInstance1.GenericArguments[i], genericInstance2.GenericArguments[i]))
+							return false;
+					}
+					return true;
+				}
+
+				if (type1 is TypeSpecification typeSpec1) {
+					if (type2 is not TypeSpecification typeSpec2)
+						return false;
+					return TypeEquals (typeSpec1.ElementType, typeSpec2.ElementType);
+				}
+				return type1.FullName == type2.FullName;
+			}
+		}
+
 		void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type)
 		{
 			if (!type.HasInterfaces)
@@ -135,8 +261,9 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type)
 
 			// Foreach interface and for each newslot virtual method on the interface, try
 			// to find the method implementation and record it.
-			foreach (var interfaceImpl in type.GetInflatedInterfaces (context)) {
-				foreach (MethodReference interfaceMethod in interfaceImpl.InflatedInterface.GetMethods (context)) {
+			var allInflatedInterface = _interfaces[type];
+			foreach (var interfaceImplementor in allInflatedInterface) {
+				foreach (MethodReference interfaceMethod in interfaceImplementor.InflatedInterface.GetMethods (context)) {
 					MethodDefinition? resolvedInterfaceMethod = context.TryResolve (interfaceMethod);
 					if (resolvedInterfaceMethod == null)
 						continue;
@@ -155,20 +282,19 @@ void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type)
 						// Try to find an implementation with a name/sig match on the current type
 						MethodDefinition? exactMatchOnType = TryMatchMethod (type, interfaceMethod);
 						if (exactMatchOnType != null) {
-							AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, new (type, interfaceImpl.OriginalImpl, resolvedInterfaceMethod.DeclaringType, context));
+							AnnotateMethods (resolvedInterfaceMethod, exactMatchOnType, interfaceImplementor);
 							continue;
 						}
 
 						// Next try to find an implementation with a name/sig match in the base hierarchy
 						var @base = GetBaseMethodInTypeHierarchy (type, interfaceMethod);
 						if (@base != null) {
-							AnnotateMethods (resolvedInterfaceMethod, @base, new (type, interfaceImpl.OriginalImpl, resolvedInterfaceMethod.DeclaringType, context));
+							AnnotateMethods (resolvedInterfaceMethod, @base, interfaceImplementor);
 							continue;
 						}
 					}
-
 					// Look for a default implementation last.
-					FindAndAddDefaultInterfaceImplementations (type, type, resolvedInterfaceMethod, interfaceImpl.OriginalImpl);
+					FindAndAddDefaultInterfaceImplementations (type, resolvedInterfaceMethod, interfaceImplementor);
 				}
 			}
 		}
@@ -198,7 +324,7 @@ void MapVirtualMethod (MethodDefinition method)
 			if (@base == null)
 				return;
 
-			Debug.Assert(!@base.DeclaringType.IsInterface);
+			Debug.Assert (!@base.DeclaringType.IsInterface);
 
 			AnnotateMethods (@base, method);
 		}
@@ -210,7 +336,9 @@ void MapOverrides (MethodDefinition method)
 				if (baseMethod == null)
 					continue;
 				if (baseMethod.DeclaringType.IsInterface) {
-					AnnotateMethods (baseMethod, method, InterfaceImplementor.Create (method.DeclaringType, baseMethod.DeclaringType, context));
+					var implr = GetInterfaceImplementor (method.DeclaringType, baseMethod.DeclaringType);
+					Debug.Assert (implr != null);
+					AnnotateMethods (baseMethod, method, implr);
 				} else {
 					AnnotateMethods (baseMethod, method);
 				}
@@ -219,8 +347,9 @@ void MapOverrides (MethodDefinition method)
 
 		void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, InterfaceImplementor? interfaceImplementor = null)
 		{
-			AddBaseMethod (@override, @base, interfaceImplementor);
-			AddOverride (@base, @override, interfaceImplementor);
+			OverrideInformation ov = new OverrideInformation (@base, @override, interfaceImplementor);
+			AddBaseMethod (@override, ov);
+			AddOverrideOfMethod (@base, ov);
 		}
 
 		MethodDefinition? GetBaseMethodInTypeHierarchy (MethodDefinition method)
@@ -282,22 +411,20 @@ void AnnotateMethods (MethodDefinition @base, MethodDefinition @override, Interf
 		/// 
 		/// The InterfaceImplementation on  that points to the DeclaringType of .
 		/// 
-		void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplementsInterface, TypeDefinition typeThatMayHaveDIM, MethodDefinition interfaceMethodToBeImplemented, InterfaceImplementation originalInterfaceImpl)
+		void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplementsInterface, MethodDefinition interfaceMethodToBeImplemented, InterfaceImplementor implr)
 		{
-			// Go over all interfaces, trying to find a method that is an explicit MethodImpl of the
-			// interface method in question.
-
-			foreach (var interfaceImpl in typeThatMayHaveDIM.Interfaces) {
-				var potentialImplInterface = context.TryResolve (interfaceImpl.InterfaceType);
-				if (potentialImplInterface == null)
-					continue;
-
+			foreach (var potentialDimProviderImplementation in _interfaces[typeThatImplementsInterface]) {
 				bool foundImpl = false;
+				if (potentialDimProviderImplementation.InterfaceType is null)
+					continue;
+				// If this interface doesn't implement the interface with the method we're looking for, it can't provide a default implementation.
+				if (GetInterfaceImplementor (potentialDimProviderImplementation.InterfaceType, interfaceMethodToBeImplemented.DeclaringType) is null)
+					continue;
 
-				foreach (var potentialImplMethod in potentialImplInterface.Methods) {
+				foreach (var potentialImplMethod in potentialDimProviderImplementation.InterfaceType.Methods) {
 					if (potentialImplMethod == interfaceMethodToBeImplemented &&
 						!potentialImplMethod.IsAbstract) {
-						AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, originalInterfaceImpl, interfaceMethodToBeImplemented.DeclaringType, context), potentialImplMethod);
+						AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, implr, potentialImplMethod);
 						foundImpl = true;
 						break;
 					}
@@ -308,22 +435,15 @@ void FindAndAddDefaultInterfaceImplementations (TypeDefinition typeThatImplement
 					// This method is an override of something. Let's see if it's the method we are looking for.
 					foreach (var baseMethod in potentialImplMethod.Overrides) {
 						if (context.TryResolve (baseMethod) == interfaceMethodToBeImplemented) {
-							AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, new (typeThatImplementsInterface, originalInterfaceImpl, interfaceMethodToBeImplemented.DeclaringType, context), @potentialImplMethod);
+							AddDefaultInterfaceImplementation (interfaceMethodToBeImplemented, implr, @potentialImplMethod);
 							foundImpl = true;
 							break;
 						}
 					}
-
 					if (foundImpl) {
 						break;
 					}
 				}
-
-				// We haven't found a MethodImpl on the current interface, but one of the interfaces
-				// this interface requires could still provide it.
-				if (!foundImpl) {
-					FindAndAddDefaultInterfaceImplementations (typeThatImplementsInterface, potentialImplInterface, interfaceMethodToBeImplemented, originalInterfaceImpl);
-				}
 			}
 		}
 
diff --git a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs
index 5092fe1158e34b..b886ad8aaa4d8a 100644
--- a/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs
+++ b/src/tools/illink/src/linker/Linker/TypeReferenceExtensions.cs
@@ -170,6 +170,13 @@ void parseArrayDimensions (ArrayType at)
 			}
 		}
 
+		public static TypeReference? TryInflateFrom (this TypeReference type, TypeReference maybeGenericInstanceProvider, ITryResolveMetadata resolver)
+		{
+			if (maybeGenericInstanceProvider is GenericInstanceType git)
+				return InflateGenericType (git, type, resolver);
+			return type;
+		}
+
 		public static TypeReference? InflateGenericType (GenericInstanceType genericInstanceProvider, TypeReference typeToInflate, ITryResolveMetadata resolver)
 		{
 			if (typeToInflate is ArrayType arrayType) {
diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.DefaultInterfaceMethodsTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.DefaultInterfaceMethodsTests.g.cs
index 4b3f387a390151..19189bfcd01705 100644
--- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.DefaultInterfaceMethodsTests.g.cs
+++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.DefaultInterfaceMethodsTests.g.cs
@@ -15,6 +15,12 @@ public Task DefaultInterfaceMethodCallIntoClass ()
 			return RunTest (allowMissingWarnings: true);
 		}
 
+		[Fact]
+		public Task DimProvidedByRecursiveInterface ()
+		{
+			return RunTest (allowMissingWarnings: true);
+		}
+
 		[Fact]
 		public Task GenericDefaultInterfaceMethods ()
 		{
@@ -39,6 +45,12 @@ public Task MostSpecificDefaultImplementationKeptStatic ()
 			return RunTest (allowMissingWarnings: true);
 		}
 
+		[Fact]
+		public Task MultipleDimsProvidedByRecursiveInterface ()
+		{
+			return RunTest (allowMissingWarnings: true);
+		}
+
 		[Fact]
 		public Task SimpleDefaultInterfaceMethod ()
 		{
@@ -51,6 +63,12 @@ public Task StaticDefaultInterfaceMethodOnStruct ()
 			return RunTest (allowMissingWarnings: true);
 		}
 
+		[Fact]
+		public Task StaticDimProvidedByUnreferencedIfaceInHierarchy ()
+		{
+			return RunTest (allowMissingWarnings: true);
+		}
+
 		[Fact]
 		public Task UnusedDefaultInterfaceImplementation ()
 		{
diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.RecursiveInterfacesTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.RecursiveInterfacesTests.g.cs
new file mode 100644
index 00000000000000..d436348e800bc7
--- /dev/null
+++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.Interfaces.RecursiveInterfacesTests.g.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace ILLink.RoslynAnalyzer.Tests.Inheritance.Interfaces
+{
+	public sealed partial class RecursiveInterfacesTests : LinkerTestBase
+	{
+
+		protected override string TestSuiteName => "Inheritance.Interfaces.RecursiveInterfaces";
+
+		[Fact]
+		public Task GenericInterfaceImplementedRecursively ()
+		{
+			return RunTest (allowMissingWarnings: true);
+		}
+
+		[Fact]
+		public Task InterfaceImplementedRecursively ()
+		{
+			return RunTest (allowMissingWarnings: true);
+		}
+
+		[Fact]
+		public Task RecursiveInterfaceKept ()
+		{
+			return RunTest (allowMissingWarnings: true);
+		}
+
+	}
+}
diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs
index 649b8449527f75..2e1a2bbcb3454d 100644
--- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs
+++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/Inheritance.InterfacesTests.g.cs
@@ -15,12 +15,6 @@ public Task CanDisableUnusedInterfaces ()
 			return RunTest (allowMissingWarnings: true);
 		}
 
-		[Fact]
-		public Task InterfaceImplementedThroughBaseInterface ()
-		{
-			return RunTest (allowMissingWarnings: true);
-		}
-
 		[Fact]
 		public Task InterfaceOnUninstantiatedTypeRemoved ()
 		{
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs
index d0d236997445ed..9fc2b77d7a4878 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/FeatureCheckDataFlow.cs
@@ -6,6 +6,7 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
+using System.Linq;
 using System.Runtime.CompilerServices;
 using System.Threading.Tasks;
 using ILLink.RoslynAnalyzer;
@@ -1155,7 +1156,8 @@ static void GuardedLocalFunction ()
 
 			public static void Test ()
 			{
-				GuardInIterator ();
+				// Use the IEnumerable to mark the IEnumerable methods
+				foreach (var _ in GuardInIterator ()) ;
 				StateFlowsAcrossYield ();
 				GuardInAsync ();
 				StateFlowsAcrossAwait ();
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/DimProvidedByRecursiveInterface.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/DimProvidedByRecursiveInterface.il
new file mode 100644
index 00000000000000..c85892208989b3
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/DimProvidedByRecursiveInterface.il
@@ -0,0 +1,86 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+.assembly extern mscorlib { }
+
+.assembly 'library' { }
+
+.class public auto ansi abstract sealed beforefieldinit Program
+    extends [mscorlib]System.Object
+{
+    // Nested Types
+    .class interface nested public auto ansi abstract beforefieldinit IFoo
+    {
+        // Methods
+        .method public hidebysig newslot abstract virtual
+            instance void Method () cil managed
+        {
+        } // end of method IFoo::Method
+
+    } // end of class IFoo
+
+    .class interface nested public auto ansi abstract beforefieldinit IBar
+        implements Program/IFoo
+    {
+        // Methods
+        .method public final hidebysig virtual
+            instance void Program.IFoo.Method () cil managed
+        {
+            .override method instance void Program/IFoo::Method()
+            // Method begins at RVA 0x2068
+            // Code size 2 (0x2)
+            .maxstack 8
+
+            IL_0000: nop
+            IL_0001: ret
+        } // end of method IBar::Program.IFoo.Method
+
+    } // end of class IBar
+
+    .class interface nested public auto ansi abstract beforefieldinit IBaz
+        implements Program/IBar
+    {
+    } // end of class IBaz
+
+    .class nested public auto ansi beforefieldinit MyFoo
+        extends [mscorlib]System.Object
+        implements Program/IBaz
+    {
+        // Methods
+        .method public hidebysig specialname rtspecialname
+            instance void .ctor () cil managed
+        {
+            // Method begins at RVA 0x2076
+            // Code size 8 (0x8)
+            .maxstack 8
+
+            IL_0000: ldarg.0
+            IL_0001: call instance void [mscorlib]System.Object::.ctor()
+            IL_0006: nop
+            IL_0007: ret
+        } // end of method MyFoo::.ctor
+
+    } // end of class MyFoo
+
+
+    // Methods
+    .method public hidebysig static
+        void CallMethod (
+            class Program/IFoo foo
+        ) cil managed
+    {
+        .custom instance void [mscorlib]mscorlib.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
+            01 00 01 00 00
+        )
+        // Method begins at RVA 0x2050
+        // Code size 9 (0x9)
+        .maxstack 8
+
+        IL_0000: nop
+        IL_0001: ldarg.0
+        IL_0002: callvirt instance void Program/IFoo::Method()
+        IL_0007: nop
+        IL_0008: ret
+    } // end of method Program::CallMethod
+
+} // end of class Program
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/MultipleDimsProvidedByRecursiveInterface.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/MultipleDimsProvidedByRecursiveInterface.il
new file mode 100644
index 00000000000000..4937513f285310
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/MultipleDimsProvidedByRecursiveInterface.il
@@ -0,0 +1,86 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+.assembly extern mscorlib { }
+
+.assembly 'library' { }
+
+.class public auto ansi abstract sealed beforefieldinit Program
+    extends [mscorlib]System.Object
+{
+    // Nested Types
+    .class interface nested public auto ansi abstract beforefieldinit I0
+    {
+        // Methods
+        .method public hidebysig newslot abstract virtual
+            instance void Method () cil managed
+        {
+        } // end of method I0::Method
+
+    } // end of class I0
+
+    .class interface nested public auto ansi abstract beforefieldinit I00
+        implements Program/I0
+    {
+        // Methods
+        .method public final hidebysig virtual
+            instance void Program.I0.Method () cil managed
+        {
+            .override method instance void Program/I0::Method()
+            // Method begins at RVA 0x2068
+            // Code size 2 (0x2)
+            .maxstack 8
+
+            IL_0000: nop
+            IL_0001: ret
+        } // end of method I00::Program.I0.Method
+    } // end of class I00
+
+    .class interface nested public auto ansi abstract beforefieldinit I01
+        implements Program/I0
+    {
+        // Methods
+        .method public final hidebysig virtual
+            instance void Program.I0.Method () cil managed
+        {
+            .override method instance void Program/I0::Method()
+            // Method begins at RVA 0x2068
+            // Code size 2 (0x2)
+            .maxstack 8
+
+            IL_0000: nop
+            IL_0001: ret
+        } // end of method I00::Program.I0.Method
+    } // end of class I00
+
+    .class interface nested public auto ansi abstract beforefieldinit I000
+        implements Program/I00
+    {
+    } // end of class I000
+
+    .class interface nested public auto ansi abstract beforefieldinit I010
+        implements Program/I01
+    {
+    } // end of class I000
+
+    .class nested public auto ansi beforefieldinit MyFoo
+        extends [mscorlib]System.Object
+        implements Program/I000, Program/I010
+    {
+        // Methods
+        .method public hidebysig specialname rtspecialname
+            instance void .ctor () cil managed
+        {
+            // Method begins at RVA 0x2076
+            // Code size 8 (0x8)
+            .maxstack 8
+
+            IL_0000: ldarg.0
+            IL_0001: call instance void [mscorlib]System.Object::.ctor()
+            IL_0006: nop
+            IL_0007: ret
+        } // end of method MyFoo::.ctor
+
+    } // end of class MyFoo
+
+} // end of class Program
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il
new file mode 100644
index 00000000000000..949d5e6fbf4aba
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il
@@ -0,0 +1,70 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+.assembly extern mscorlib { }
+
+.assembly 'library' { }
+
+.class public auto ansi abstract sealed beforefieldinit Program
+    extends [mscorlib]System.Object
+{
+    // Nested Types
+    .class interface nested public auto ansi abstract beforefieldinit IBase
+    {
+        // Methods
+        .method public hidebysig abstract virtual static
+            void Method () cil managed
+        {
+        } // end of method IBase::Method
+
+    } // end of class IBase
+
+    .class interface nested public auto ansi abstract beforefieldinit I2
+        implements Program/IBase
+    {
+        // Methods
+        .method public hidebysig static
+            void Program.IBase.Method () cil managed
+        {
+            .override method void Program/IBase::Method()
+            // Method begins at RVA 0x205f
+            // Code size 2 (0x2)
+            .maxstack 8
+
+            IL_0000: nop
+            IL_0001: ret
+        } // end of method I2::Program.IBase.Method
+
+    } // end of class I2
+
+    .class interface nested public auto ansi abstract beforefieldinit I3
+        implements Program/I2
+    {
+    } // end of class I3
+
+    .class interface nested public auto ansi abstract beforefieldinit I4
+        implements Program/I3
+    {
+    } // end of class I4
+
+
+    // Methods
+    .method public hidebysig static
+        void CallMethod<(Program/IBase) T> () cil managed
+    {
+        .param constraint T, Program/IBase
+            .custom instance void [mscorlib]mscorlib.CompilerServices.NullableAttribute::.ctor(uint8) = (
+                01 00 01 00 00
+            )
+        // Method begins at RVA 0x2050
+        // Code size 14 (0xe)
+        .maxstack 8
+
+        IL_0000: nop
+        IL_0001: constrained. !!T
+        IL_0007: call void Program/IBase::Method()
+        IL_000c: nop
+        IL_000d: ret
+    } // end of method Program::CallMethod
+
+} // end of class Program
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByRecursiveInterface.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByRecursiveInterface.cs
new file mode 100644
index 00000000000000..743df7227a80c8
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/DimProvidedByRecursiveInterface.cs
@@ -0,0 +1,67 @@
+
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods
+{
+	[SetupLinkerArgument ("--skip-unresolved", "true")]
+	[TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")]
+	[Define ("IL_ASSEMBLY_AVAILABLE")]
+	[SetupCompileBefore ("library.dll", new[] { "Dependencies/DimProvidedByRecursiveInterface.il" })]
+	[SkipILVerify]
+
+#if IL_ASSEMBLY_AVAILABLE
+	[KeptMemberInAssembly ("library.dll", typeof(Program.IFoo), "Method()")]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IBar))]
+	[KeptMemberInAssembly ("library.dll", typeof(Program.IBar), "Program.IFoo.Method()")]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IBar), "library.dll", typeof (Program.IFoo))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.MyFoo), "library.dll", typeof (Program.IBaz))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IBaz))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IBaz), "library.dll", typeof (Program.IBar))]
+	[KeptMemberInAssembly ("library.dll", typeof(Program), "CallMethod(Program/IFoo)")]
+#endif
+	class DimProvidedByRecursiveInterface
+	{
+		static void Main ()
+		{
+#if IL_ASSEMBLY_AVAILABLE
+			Program.IFoo foo = new Program.MyFoo ();
+			Program.CallMethod(foo);
+#endif
+		}
+	}
+}
+
+
+
+// public static class Program
+// {
+// 	[Kept]
+// 	interface IFoo
+// 	{
+// 		void Method();
+// 	}
+
+// 	[Kept]
+// 	interface IBar : IFoo
+// 	{
+// 		[Kept]
+// 		void IFoo.Method() { }
+// 	}
+
+// 	[Kept]
+// 	interface IBaz: IBar /* not IFoo */
+// 	{
+// 	}
+
+// 	[Kept]
+// 	[KeptInterface(typeof(IBaz))]
+// 	class MyFoo : IBaz /* not IBar, not IFoo */
+// 	{ }
+
+// 	static void CallMethod(IFoo foo)
+// 	{
+// 		foo.Method();
+// 	}
+// }
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/MultipleDimsProvidedByRecursiveInterface.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/MultipleDimsProvidedByRecursiveInterface.cs
new file mode 100644
index 00000000000000..7d027825ec4092
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/MultipleDimsProvidedByRecursiveInterface.cs
@@ -0,0 +1,86 @@
+
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods
+{
+	[SetupLinkerArgument ("--skip-unresolved", "true")]
+	[TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")]
+	[Define ("IL_ASSEMBLY_AVAILABLE")]
+	[SetupCompileBefore ("library.dll", new[] { "Dependencies/MultipleDimsProvidedByRecursiveInterface.il" })]
+	[SkipILVerify]
+
+#if IL_ASSEMBLY_AVAILABLE
+	// Both DIMs on I01 and I00 should be kept because one is not more specific than another.
+	[KeptMemberInAssembly ("library.dll", typeof(Program.I0), "Method()")]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.I00))]
+	[KeptMemberInAssembly ("library.dll", typeof(Program.I00), "Program.I0.Method()")]
+	[KeptMemberInAssembly ("library.dll", typeof(Program.I01), "Program.I0.Method()")]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I00), "library.dll", typeof (Program.I0))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.MyFoo), "library.dll", typeof (Program.I000))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.I000))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I000), "library.dll", typeof (Program.I00))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.MyFoo), "library.dll", typeof (Program.I010))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I010), "library.dll", typeof (Program.I01))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I01), "library.dll", typeof (Program.I0))]
+#endif
+	class MultipleDimsProvidedByRecursiveInterface
+	{
+		static void Main ()
+		{
+#if IL_ASSEMBLY_AVAILABLE
+			Program.I0 foo = new Program.MyFoo ();
+			CallMethod(foo);
+#endif
+		}
+#if IL_ASSEMBLY_AVAILABLE
+		[Kept]
+		static void CallMethod(Program.I0 foo)
+		{
+			foo.Method();
+		}
+#endif
+	}
+}
+
+
+
+// public static class Program
+// {
+// 	[Kept]
+// 	interface I0
+// 	{
+// 		void Method();
+// 	}
+
+// 	[Kept]
+// 	interface I00 : I0
+// 	{
+// 		[Kept]
+// 		void I0.Method() { }
+// 	}
+
+// 	[Kept]
+// 	interface I000: I00 /* not I0 */
+// 	{
+// 	}
+
+// 	[Kept]
+// 	interface I01 : I0
+// 	{
+// 		[Kept]
+// 		void I0.Method() { }
+// 	}
+
+// 	[Kept]
+// 	interface I010: I01 /* not I0 */
+// 	{
+// 	}
+
+// 	[Kept]
+// 	[KeptInterface(typeof(I000))]
+// 	class MyFoo : I000, I010
+// 	{ }
+
+// }
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs
new file mode 100644
index 00000000000000..2d10e78d146f35
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/DefaultInterfaceMethods/StaticDimProvidedByUnreferencedIfaceInHierarchy.cs
@@ -0,0 +1,69 @@
+
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.DefaultInterfaceMethods
+{
+	[SetupLinkerArgument ("--skip-unresolved", "true")]
+	[TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")]
+	[Define ("IL_ASSEMBLY_AVAILABLE")]
+	[SetupCompileBefore ("library.dll", new[] { "Dependencies/StaticDimProvidedByUnreferencedIfaceInHierarchy.il" })]
+	[SkipILVerify]
+
+#if IL_ASSEMBLY_AVAILABLE
+	[KeptMemberInAssembly ("library.dll", typeof(Program), "CallMethod<#1>()")]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IBase))]
+	[KeptMemberInAssembly ("library.dll", typeof(Program.IBase), "Method()")]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.I4))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.I2))]
+	[KeptMemberInAssembly ("library.dll", typeof(Program.I2), "Program.IBase.Method()")]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I2), "library.dll", typeof (Program.IBase))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.I3))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I3), "library.dll", typeof (Program.I2))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.I4), "library.dll", typeof (Program.I3))]
+#endif
+	class StaticDimProvidedByUnreferencedIfaceInHierarchy
+	{
+		static void Main ()
+		{
+#if IL_ASSEMBLY_AVAILABLE
+			Program.CallMethod();
+#endif
+		}
+	}
+}
+
+
+
+// public static class Program
+// {
+//	[Kept]
+//	interface IBase
+//	{
+//		[Kept]
+// 		static abstract void Method();
+// 	}
+
+//	[Kept]
+//	[KeptInterface(typeof(IBase)]
+//	interface I2 : IBase
+//	{
+//		[Kept]
+//		static void IBase.Method() { }
+//	}
+
+//	[Kept]
+// 	[KeptInterface(typeof(I2)]
+// 	interface I3 : I2 { }
+
+//	[Kept]
+//	[KeptInterface(typeof(I3)]
+//	interface I4 : I3 { }
+
+//	[Kept]
+//	static void CallMethod() where T : IBase
+//	{
+//		T.Method();
+//	}
+// }
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/InterfaceImplementedThroughBaseInterface.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/InterfaceImplementedThroughBaseInterface.il
deleted file mode 100644
index 61080f8b7d066d..00000000000000
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/Dependencies/InterfaceImplementedThroughBaseInterface.il
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-.assembly extern mscorlib { }
-
-.assembly 'library' { }
-
-.class interface public auto ansi abstract beforefieldinit IBase
-{
-    // Methods
-    .method public hidebysig newslot abstract virtual 
-        instance void M () cil managed 
-    {
-    } // end of method IBase::M
-
-} // end of class IBase
-
-.class interface public auto ansi abstract beforefieldinit IDerived
-    implements IBase
-{
-} // end of class IDerived
-
-.class public auto ansi beforefieldinit C
-    extends [System.Runtime]System.Object
-    implements IDerived
-{
-    // Methods
-    .method private final hidebysig newslot virtual 
-        instance void IBase.M () cil managed 
-    {
-        .override method instance void IBase::M()
-        // Method begins at RVA 0x2050
-        // Code size 2 (0x2)
-        .maxstack 8
-
-        IL_0001: ret
-    } // end of method C::IBase.M
-
-    .method public hidebysig specialname rtspecialname 
-        instance void .ctor () cil managed 
-    {
-        // Method begins at RVA 0x2053
-        // Code size 8 (0x8)
-        .maxstack 8
-
-        IL_0007: ret
-    } // end of method C::.ctor
-}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceImplementedThroughBaseInterface.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceImplementedThroughBaseInterface.cs
deleted file mode 100644
index e701fb9c28ba61..00000000000000
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/InterfaceImplementedThroughBaseInterface.cs
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) .NET Foundation and contributors. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Mono.Linker.Tests.Cases.Expectations.Assertions;
-using Mono.Linker.Tests.Cases.Expectations.Metadata;
-
-namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces
-{
-	[SetupLinkerArgument ("--skip-unresolved", "true")]
-	[SetupLinkerArgument ("-a", "test.exe", "library")]
-	[SetupLinkerArgument ("-a", "library.dll", "library")]
-	[TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")]
-	[Define ("IL_ASSEMBLY_AVAILABLE")]
-	[SetupCompileBefore ("library.dll", new[] { "Dependencies/InterfaceImplementedThroughBaseInterface.il" })]
-	[SkipILVerify]
-
-#if IL_ASSEMBLY_AVAILABLE
-	[KeptMemberInAssembly ("library.dll", typeof(C), "IBase.M()")]
-#endif
-	[KeptMember(".ctor()")]
-	public class InterfaceImplementedThroughBaseInterface
-	{
-		public static void Main ()
-		{
-		}
-	}
-}
-
-
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/GenericInterfaceWithMethodManyVariations.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/GenericInterfaceWithMethodManyVariations.cs
index 078f4b94c60ba6..79ad8eaaa58c2c 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/GenericInterfaceWithMethodManyVariations.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/BaseProvidesInterfaceMember/GenericInterfaceWithMethodManyVariations.cs
@@ -68,4 +68,4 @@ class Bar
 		{
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/GenericInterfaceImplementedRecursively.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/GenericInterfaceImplementedRecursively.il
new file mode 100644
index 00000000000000..7ff59e54ad0658
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/GenericInterfaceImplementedRecursively.il
@@ -0,0 +1,45 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+.assembly extern mscorlib { }
+
+.assembly 'library' { }
+
+.class public auto ansi abstract sealed beforefieldinit Program
+    extends [mscorlib]System.Object
+{
+    // Nested Types
+    .class interface nested public auto ansi abstract beforefieldinit IBase`1
+    {
+    } // end of class IBase
+
+    .class interface nested public auto ansi abstract beforefieldinit IMiddle`1
+        implements class Program/IBase`1
+    {
+    } // end of class IMiddle
+
+    .class interface nested public auto ansi abstract beforefieldinit IDerived`1
+        implements class Program/IMiddle`1
+    {
+    } // end of class IDerived
+
+    .class nested public auto ansi beforefieldinit C
+        extends [mscorlib]System.Object
+        implements class Program/IDerived`1
+    {
+        // Methods
+        .method public hidebysig specialname rtspecialname
+            instance void .ctor () cil managed
+        {
+            // Method begins at RVA 0x2066
+            // Code size 8 (0x8)
+            .maxstack 8
+
+            IL_0000: ldarg.0
+            IL_0001: call instance void [mscorlib]System.Object::.ctor()
+            IL_0006: nop
+            IL_0007: ret
+        } // end of method C::.ctor
+
+    } // end of class C
+} // end of class Program
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/InterfaceImplementedRecursively.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/InterfaceImplementedRecursively.il
new file mode 100644
index 00000000000000..c1d2943997da6f
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/InterfaceImplementedRecursively.il
@@ -0,0 +1,67 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+.assembly extern mscorlib { }
+
+.assembly 'library' { }
+
+.class public auto ansi abstract sealed beforefieldinit Program
+    extends [System.Runtime]System.Object
+{
+    // Nested Types
+    .class interface nested public auto ansi abstract beforefieldinit IBase
+    {
+    } // end of class IBase
+
+    .class interface nested public auto ansi abstract beforefieldinit IMiddle
+        implements Program/IBase
+    {
+    } // end of class IMiddle
+
+    .class interface nested public auto ansi abstract beforefieldinit IDerived
+        implements Program/IMiddle
+    {
+    } // end of class IDerived
+
+    .class nested public auto ansi beforefieldinit C
+        extends [System.Runtime]System.Object
+        implements Program/IDerived
+    {
+        // Methods
+        .method public hidebysig specialname rtspecialname
+            instance void .ctor () cil managed
+        {
+            // Method begins at RVA 0x2066
+            // Code size 8 (0x8)
+            .maxstack 8
+
+            IL_0000: ldarg.0
+            IL_0001: call instance void [System.Runtime]System.Object::.ctor()
+            IL_0006: nop
+            IL_0007: ret
+        } // end of method C::.ctor
+
+    } // end of class C
+
+
+    // Methods
+    .method public hidebysig static
+        void Main () cil managed
+    {
+        // Method begins at RVA 0x2050
+        // Code size 10 (0xa)
+        .maxstack 1
+        .locals init (
+            [0] class Program/IBase b,
+            [1] class Program/C c
+        )
+
+        IL_0000: nop
+        IL_0001: ldnull
+        IL_0002: stloc.0
+        IL_0003: newobj instance void Program/C::.ctor()
+        IL_0008: stloc.1
+        IL_0009: ret
+    } // end of method Program::Main
+
+} // end of class Program
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/RecursiveInterfaceTwoImplementationPaths.il b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/RecursiveInterfaceTwoImplementationPaths.il
new file mode 100644
index 00000000000000..854b0cd4a45b20
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/Dependencies/RecursiveInterfaceTwoImplementationPaths.il
@@ -0,0 +1,62 @@
+
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+.assembly extern mscorlib { }
+
+.assembly 'library' { }
+
+.class public auto ansi abstract sealed beforefieldinit Library
+    extends [mscorlib]System.Object
+{
+    .class interface nested public auto ansi abstract beforefieldinit I0
+    {
+    } // end of class I0
+
+    .class interface nested public auto ansi abstract beforefieldinit I00
+        implements Library/I0
+    {
+    } // end of class I00
+
+    .class interface nested public auto ansi abstract beforefieldinit I01
+        implements Library/I0
+    {
+    } // end of class I01
+
+    .class interface nested public auto ansi abstract beforefieldinit I000
+        implements Library/I00
+    {
+    } // end of class I000
+
+    .class interface nested public auto ansi abstract beforefieldinit I010
+        implements Library/I01
+    {
+    } // end of class I010
+
+    .class interface nested public auto ansi abstract beforefieldinit I0100
+        implements Library/I010
+    {
+    } // end of class I010
+
+    .class nested public auto ansi beforefieldinit MyClass
+        extends [mscorlib]System.Object
+        implements Library/I0100,
+                   Library/I000
+    {
+        // Methods
+        .method public hidebysig specialname rtspecialname
+            instance void .ctor () cil managed
+        {
+            // Method begins at RVA 0x2076
+            // Code size 8 (0x8)
+            .maxstack 8
+
+            IL_0000: ldarg.0
+            IL_0001: call instance void [mscorlib]System.Object::.ctor()
+            IL_0006: nop
+            IL_0007: ret
+        } // end of method MyFoo::.ctor
+
+    } // end of class MyFoo
+
+} // end of class Library
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/GenericInterfaceImplementedRecursively.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/GenericInterfaceImplementedRecursively.cs
new file mode 100644
index 00000000000000..bb0d318cac1a1d
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/GenericInterfaceImplementedRecursively.cs
@@ -0,0 +1,42 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.RecursiveInterfaces
+{
+	[SetupLinkerArgument ("--skip-unresolved", "true")]
+	[TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")]
+	[Define ("IL_ASSEMBLY_AVAILABLE")]
+	[SetupCompileBefore ("library.dll", new[] { "Dependencies/GenericInterfaceImplementedRecursively.il" })]
+	[SkipILVerify]
+#if IL_ASSEMBLY_AVAILABLE
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IBase<>))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IMiddle<>))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IMiddle<>), "library.dll", typeof (Program.IBase<>))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IDerived<>))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IDerived<>), "library.dll", typeof (Program.IMiddle<>))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.C))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.C), "library.dll", typeof (Program.IDerived))]
+#endif
+	/// 
+	/// This test case is to verify that the linker will keep all the metadata necessary for C to implement IBase when an interfaceImpl isn't directly on C.
+	/// 
+	class GenericInterfaceImplementedRecursively
+	{
+		public static void Main()
+		{
+
+#if IL_ASSEMBLY_AVAILABLE
+			Program.IBase _ = null;
+			_ = new Program.C();
+#endif
+		}
+	}
+}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/InterfaceImplementedRecursively.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/InterfaceImplementedRecursively.cs
new file mode 100644
index 00000000000000..89f59777c5fcd0
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/InterfaceImplementedRecursively.cs
@@ -0,0 +1,49 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.RecursiveInterfaces
+{
+	[SetupLinkerArgument ("--skip-unresolved", "true")]
+	[TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")]
+	[Define ("IL_ASSEMBLY_AVAILABLE")]
+	[SetupCompileBefore ("library.dll", new[] { "Dependencies/InterfaceImplementedRecursively.il" })]
+	[SkipILVerify]
+#if IL_ASSEMBLY_AVAILABLE
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IBase))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IMiddle))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IMiddle), "library.dll", typeof (Program.IBase))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.IDerived))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.IDerived), "library.dll", typeof (Program.IMiddle))]
+	[KeptTypeInAssembly ("library.dll", typeof(Program.C))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Program.C), "library.dll", typeof (Program.IDerived))]
+#endif
+	/// 
+	/// This test case is to verify that the linker will keep all the metadata necessary for C to implement IBase when an interfaceImpl isn't directly on C.
+	/// 
+	class InterfaceImplementedRecursively
+	{
+		public static void Main()
+		{
+
+#if IL_ASSEMBLY_AVAILABLE
+			Program.IBase b = null;
+			object c = new Program.C();
+
+#endif
+		}
+	}
+	// interface IBase {}
+	// interface IMiddle : IBase {}
+	// interface IDerived : IMiddle {}
+	// class C : IDerived
+	// {
+	// }
+}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/RecursiveInterfaceKept.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/RecursiveInterfaceKept.cs
new file mode 100644
index 00000000000000..56e08d67be74f7
--- /dev/null
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/RecursiveInterfaces/RecursiveInterfaceKept.cs
@@ -0,0 +1,36 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.RecursiveInterfaces
+{
+	/// 
+	/// This tests that when a type implements an interface recursively (via implementations on implemented interfaces),
+	/// the interface implementations kept are in type declaration order according to ECMA-335 12.2
+	/// 
+	[TestCaseRequirements (TestRunCharacteristics.SupportsDefaultInterfaceMethods, "Requires support for default interface methods")]
+	[Define ("IL_ASSEMBLY_AVAILABLE")]
+	[SetupCompileBefore ("library.dll", new[] { "Dependencies/RecursiveInterfaceTwoImplementationPaths.il" })]
+	[SkipILVerify]
+#if IL_ASSEMBLY_AVAILABLE
+	[KeptTypeInAssembly ("library.dll", typeof(Library.MyClass))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Library.MyClass), "library.dll", typeof (Library.I0100))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Library.I0100), "library.dll", typeof (Library.I010))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Library.I010), "library.dll", typeof (Library.I01))]
+	[KeptInterfaceOnTypeInAssembly ("library.dll", typeof (Library.I01), "library.dll", typeof (Library.I0))]
+	[RemovedTypeInAssembly("library.dll", typeof(Library.I00))]
+	[RemovedTypeInAssembly("library.dll", typeof(Library.I000))]
+	[RemovedInterfaceOnTypeInAssembly("library.dll", typeof (Library.MyClass), "library.dll", typeof (Library.I000))]
+#endif
+	public class RecursiveInterfaceKept
+	{
+		public static void Main()
+		{
+#if IL_ASSEMBLY_AVAILABLE
+			Library.I0 _ = new Library.MyClass();
+#endif
+		}
+	}
+}
diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/UnreachableBlock/CompilerGeneratedCodeSubstitutions.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/UnreachableBlock/CompilerGeneratedCodeSubstitutions.cs
index 5b1edc37671ace..3c59c3e446aadb 100644
--- a/src/tools/illink/test/Mono.Linker.Tests.Cases/UnreachableBlock/CompilerGeneratedCodeSubstitutions.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/UnreachableBlock/CompilerGeneratedCodeSubstitutions.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
+using System.Linq;
 using System.Threading.Tasks;
 using Mono.Linker.Tests.Cases.Expectations.Assertions;
 using Mono.Linker.Tests.Cases.Expectations.Metadata;
@@ -174,7 +175,8 @@ static IEnumerable TestBranchWithYieldBefore ()
 
 			public static void Test ()
 			{
-				TestBranchWithNormalCall ();
+				// Use the IEnumerable to mark the IEnumerable methods
+				foreach (var _ in TestBranchWithNormalCall ()) ;
 				TestBranchWithYieldAfter ();
 				TestBranchWithYieldBefore ();
 			}
diff --git a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
index 8ed15724cc1148..467c2272c1bed4 100644
--- a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
+++ b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs
@@ -345,7 +345,7 @@ IEnumerable VerifyInterfaces (TypeDefinition src, TypeDefinition linked)
 				}
 
 				if (expectedInterfaces.Any ()) {
-					yield return $"Expected interfaces were not found on {src}";
+					yield return $"Expected interfaces were not found on {src}. Expected to find: \n{string.Join(Environment.NewLine, expectedInterfaces)}\n";
 				}
 			}
 		}