When you use a type parameter to abstract over actual data in your ADT, there is typically only one variance that makes sense, if you choose to incorporate subtyping into your designs at all. This is the natural, “parametrically sound” variance. sealed abstract class MyModel[P, I, -T, +V] final case class Running[I, T, V]( run: (I, T) => V ) extends MyModel[String, I, T, V] final case class Inject[I]( config: I ) extends MyModel[Int, I, Any, Nothing] There are only four interesting possib...