First source of confusion: in C# we have conflated two completely different operations as 'cast' operations. The two operations that we have conflated are what the CLR calls casts and coercions. 8.3.2 Coercion Sometimes it is desirable to take a value of a type that is not assignment-compatible with a location, and convert the value to a type that is assignment-compatible. This is accomplished through coercion of the value. Coercion takes a value of a particular type and a desired type and attempts to create a value of the desired type that has equivalent meaning to the original value. Coercion can result in representation changes as well as type changes; hence coercion does not necessarily preserve the identity of two objects. There are two kinds of coercion: widening, which never loses information, and narrowing, in which information might be lost. An example of a widening coercion would be coercing a value that is a 32-bit signed integer to a value that is a 64-bit signed integer. An example of a narrowing coercion is the reverse: coercing a 64- bit signed integer to a 32-bit signed integer. Programming languages often implement widening coercions as implicit conversions, whereas narrowing coercions usually require an explicit conversion. Some widening coercion is built directly into the VES operations on the built-in types (see �12.1). All other coercion shall be explicitly requested. For the built-in types, the CTS provides operations to perform widening coercions with no runtime checks and narrowing coercions with runtime checks. 8.3.3 Casting Since a value can be of more than one type, a use of the value needs to clearly identify which of its types is being used. Since values are read from locations that are typed, the type of the value which is used is the type of the location from which the value was read. If a different type is to be used, the value is cast to one of its other types. Casting is usually a compile time operation, but if the compiler cannot statically know that the value is of the target type, a runtime cast check is done. Unlike coercion, a cast never changes the actual type of an object nor does it change the representation. Casting preserves the identity of objects. For example, a runtime check might be needed when casting a value read from a location that is typed as holding a value of a particular interface. Since an interface is an incomplete description of the value, casting that value to be of a different interface type will usually result in a runtime cast check. We conflate these two things in C#, using the same operator syntax and terminology for both casts and coercions. So now it should be clear that there is no 'cast' from int to float in the CLR. That's a coercion, not a cast. Second source of confusion: inconsistency in the CLR spec. The CLR spec says in section 8.7 Signed and unsigned integral primitive types can be assigned to each other; e.g., int8 := uint8 is valid. For this purpose, bool shall be considered compatible with uint8 and vice versa, which makes bool := uint8 valid, and vice versa. This is also true for arrays of signed and unsigned integral primitive types of the same size; e.g., int32 := uint32 is valid.