When it comes to collections, generics make it possible to avoid boxing/unboxing by utilizing actual T[] arrays internally. List<T> for example uses a T[] array to store its contents.
The array, of course, is a reference type and is therefore (in the current version of the CLR, yada yada) stored on the heap. But since it’s a T[] and not an object[], the array’s elements can be stored “directly”: that is, they’re still on the heap, but they’re on the heap in the array instead of being boxed and having the array contain references to the boxes.
So for a List<int>, for example, what you’d have in the array would “look” like this:
[ 1 2 3 ]
Compare this to an ArrayList, which uses an object[] and would therefore “look” something like this:
[ *a *b *c ]
…where *a, etc. are references to objects (boxed integers):
*a -> 1 *b -> 2 *c -> 3
Excuse those crude illustrations; hopefully you know what I mean.