Herencia forzada VB.NET a través de múltiples generaciones

Estoy tratando de envolver mi cabeza alrededor de la herencia / interfaces / implementación un poco mejor en .NET.

Tengo una clase que se define de la siguiente manera (tipo de):

Public Class Sheet
    Property Name As String
    Property Steps As List(Of [Step])
End Class

La cosa es que [Step] es solo una clase base virtual. Hay 5 diferentes implementaciones concretas de [Step]. Para hacer las cosas un poco más complejas, hay 3 implementaciones DIRECTAS de [Step], 2 de las cuales son virtuales. Cada uno de esos 2 tiene 2 subclases que implementarán concretamente [Paso].

Entonces, así es como se ve:

                          Step
         |-----------------|-----------------|
         |                 |                 |
     SubStepA          SubStepB          SubStepC
    |----|----|                         |----|----|
    |         |                         |         |
SubStepAA SubStepAB                 SubStepCA SubStepCB

Por lo tanto, SubStepB, SubStepAA, SubStepAB, SubStepCA y SubStepCB son las implementaciones concretas.

Hay un par de cosas que me gustaría HACER CUALQUIER Paso, como Clone ().

Entonces, traté de declarar lo siguiente en el Paso:

Public MustOverride Function Clone() As Step

El problema es que, cuando intento implementar eso en SubStepAA, no puedo declarar lo siguiente:

Public Overrides Function Clone() As SubStepAA

Si hago eso, recibo un error de que los tipos de retorno no son los mismos.

¿Es la solución a esto simplemente usar una llamada DirectCast cada vez que clone una subclase concreta? Eso parece extraño e insatisfactorio. También parece mal. Quiero decir, si clono un objeto SubStepAA, quiero recuperar un objeto de tipo SubStepAA.

Tiene que haber una manera de hacer esto, ¿verdad? Quiero decir, supongo que podría declarar cada clase como debe ser, pero también parece incorrecto tener que escribir 5 métodos DIFERENTES de clonar () que SUCEDEN que funcionen (esencialmente) de la misma manera (creando una copia profunda del objeto referenciado).

He investigado el uso de declaraciones de interfaz, pero eso parece sufrir el mismo error de falta de coincidencia de tipo.

Por favor, dime que me estoy perdiendo algo básico!

¡Gracias!

Además, he estado leyendo un poco y me doy cuenta de que puede haber formas más optimizadas de hacer copias en profundidad del objeto (por ejemplo, a través de la serialización / deserialización), pero todavía estoy interesado en esta pregunta, incluso si elijo Clonar objetos utilizando un enfoque diferente.