You can express the constraint via a type argument on Bed.apply instead of via a type equality constraint,
object Bed {
def apply[T1](
a1: Animal { type Species = T1 },
b1: Animal { type Species = T1 }) = new Bed {
type T = T1
def a = a1
def b = b1
}
}
This can be made a little terser with the aid of a type alias,
type AnimalAux[S] = Animal { type Species = S }
object Bed {
def apply[T1](a1: AnimalAux[T1], b1: AnimalAux[T1]) =
new Bed {
type T = T1
def a = a1
def b = b1
}
}
Sample REPL session,
scala> trait Dog
defined trait Dog
scala> val tigger = new Animal { type Species = Dog }
tigger: Animal{type Species = Dog} = $anon$1@64bd8f9c
scala> val zebedee = new Animal { type Species = Dog }
zebedee: Animal{type Species = Dog} = $anon$1@61f2bf35
scala> Bed(tigger, zebedee)
res0: Bed{type T = Dog} = Bed$$anon$1@2b0ce330
scala> val b = Bed(tigger, zebedee)
b: Bed{type T = Dog} = Bed$$anon$1@681c81de