What is important here is to distinguish between data and representation. When you input an integer, you actually input a representation of the integer. That is, even without specifying the base, you don't enter the integer 42 (you would be hard-pressed to do that), but the decimal representation of the integer, consisting of the two digits 4 and 2, in that order, i.e. the string 42. However Mathematica doesn't store it in that way; it would be impractical to do so. Instead it stores it in an internal, binary representation which matches the representation the processor uses for numbers. Finally when printing, it takes the internal representation and converts it to the decimal representaion, thus printing 42 again.
Now Mathematica allows you to input numbers in different representations, in your case, base 16 with a to f as extra digits. That is, if you type 16^^2a, Mathematica recognizes this as another representation of the same integer 42, and therefore also converts it into the internal representation of that integer. Then when displaying it, the printing code has no idea about where that integer it has to print comes from, you might have entered it in decimal form, in hexadecimal form, or you might not have entered it at all, but it might have been the result of a calculation like HitchHikerEvaluate[6 * 9]. All the printing routine knows is that here's an internal representation of the number 42 to print. And it does so by converting it into decimal, resulting in the output 42.
Note that conversion to internal form is not done by the evaluator. The evaluator takes an expression in internal form and evaluates that in order to get another expression in internal form. Conversion of input representation into internal representation, known as parsing, happens before the evaluation gets to see it, and it has to because the evaluator cannot act on the input, it only can act on the internal representation. Indeed, in your expression FullForm[16^^abcdef] it is the parsing which reveals that there's an expression with head FullForm and a single argument of type Integer. That is, at the time the expression exists (as result of parsing the input) the base already is gone.
Note that you can modify parsing as well. For the Front End, there's the Notation package which allows you to tell Mathematica how to interpret certain box structures you enter. And there's $PreRead which is applied to the input form before it is parsed. This way, it might be possible to change all base^^num expressions into some expression basenum[base, value] and implement arithmetics for that so that it acts mostly like an integer, except that it displays in base^^num form. Maybe an alternative would be to transform it into Interpretation["base^^num", value]. However I'm not sure how well that would work.
IntegerString[16^^abcdef, 16]would be acceptable for your application. – whuber Apr 23 '12 at 18:56