Covariance works like you describe, but there is one important piece:
A generic class is only covariant if it inherits from an interface marked with the "out" keyword on the covariant generic parameter.
There are a bunch of rules on how you can use this, see MSDN for details.
You aren't inheriting a covariant interface, so your derived assignments will break.
You need something like:
IGeneric<out T>
{
}
class a<T> : IGeneric<T>
{
}
and so on. Your assignments should work as long as it looks like:
IGeneric<Base> = a<Derived>