I'm reading some ECMA-335 text today, which is about the design of dotnet CLI. There's something called typed reference there, which consist of static data type and the address of data, which reminds me of the trait objects in rust.
So, in rust, one way to think about the trait objects is: it's actually a more generic type constrained by const generics, taking some metadata matching a trait as the constant, and the resulting type automatically implements the trait.
And by removing the constant bound, maybe there can be a dynany type. Its relationship to dyn Trait is just like &[T] to &[T; 3]. Using a AsRef/AsMut, the Trait part of &dyn Trait can be erased, transformed into a &dynany type, and by specifying the metadata for some trait as constant generics, &dynany can TryInto some &dyn Trait.
In this idea, Box<dynany> can supply uniform storage for every value, and &dynany can supply uniform storage for shared pointers.
(Side note: its usefulness/necessity is much more limited in Rust. I have no idea about how idiomatic/widespread/useful/necessary it is on the CLR, but usually in Rust it certainly is/should be a last resort solution, unlike strongly-typed existentials.)
You can add other methods to this to convert between other pointer types. There's even a crate that does this for you, if only I could remember its name.
Then you use this extension trait instead of the bae trait, and everything works out.