What you describe are existential types, a feature that every statically-typed language with parametric polymorphism has, either through some explicit syntactic feature (Rust traits, Haskell type classes, ML modules), or even without, as from basic logic and the Curry–Howard correspondence you can always encode an existential using universals.
Some static languages had existentials even before they got parametric polymorphism (Go interfaces). This is why we could do so much in Go without generics!