I'm surprised they need so many bits.. you really just need to know if the item is an object (so the type can be embedded in the object), or a primitive type. But there are not so many primitive types.
Some dynamically typed systems put the tag at the beginning of a page: so all items of a particular type are allocated out of a page tagged with that type. You don't waste any bits from the pointer or data, but you do have to do some masking and worse, a remote memory access to get the type.
Probably safest and fastest to do something like: struct { int type; union { char *s; int n; double d; }};