TypeConverter cannot convert from some base types to same base types

Boolean, Char, DateTime, String and Object's TypeConverter inherit from BaseTypeConverter and don't overwrite CanConvertTo, which return true only if the type passed is of type string. That is why TypeDescriptor.GetConverter(typeof(bool)).CanConvertTo(typeof(bool)) is false.

The type converters for Byte, Double, Int16, Int32, Int64, SByte, Single, UInt16, UInt32, and UInt64 are all derived from BaseNumberConverter which returns true for CanCovertTo for types that are strings or primitive types.

Decimal does inherit from BaseNumberConverter as well, but since it's not a primitive, passing decimal type to CanConvertTo will result in false. That is why TypeDescriptor.GetConverter(typeof(decimal)).CanConvertTo(typeof(decimal)) is false.

Here's a full chart for the results of CanConvertTo:

FROM/TO     Bol Byt Chr DTm Dec Dbl I16 I32 I64 SBt Sng Str Obj U16 U32 U64
Boolean                                                 +               
Byte        +   +   +           +   +   +   +   +   +   +       +   +   +
Char                                                    +               
DateTime                                                +               
Decimal     +   +   +           +   +   +   +   +   +   +       +   +   +
Double      +   +   +           +   +   +   +   +   +   +       +   +   +
Int16       +   +   +           +   +   +   +   +   +   +       +   +   +
Int32       +   +   +           +   +   +   +   +   +   +       +   +   +
Int64       +   +   +           +   +   +   +   +   +   +       +   +   +
SByte       +   +   +           +   +   +   +   +   +   +       +   +   +
Single      +   +   +           +   +   +   +   +   +   +       +   +   +
String                                                  +               
Object                                                  +               
UInt16      +   +   +           +   +   +   +   +   +   +       +   +   +
UInt32      +   +   +           +   +   +   +   +   +   +       +   +   +
UInt64      +   +   +           +   +   +   +   +   +   +       +   +   +

Types and their converters:

Type        Converter class     Converter inherits from
----------  ------------------  -----------------------
Boolean     BooleanConverter    TypeConverter
Byte        ByteConverter       BaseNumberConverter
Char        CharConverter       TypeConverter
DateTime    DateTimeConverter   TypeConverter
Decimal     DecimalConverter    BaseNumberConverter
Double      DoubleConverter     BaseNumberConverter
Int16       Int16Converter      BaseNumberConverter
Int32       Int32Converter      BaseNumberConverter
Int64       Int64Converter      BaseNumberConverter
SByte       SByteConverter      BaseNumberConverter
Single      SingleConverter     BaseNumberConverter
String      StringConverter     TypeConverter
Object      TypeConverter       Object
UInt16      UInt16Converter     BaseNumberConverter
UInt32      UInt32Converter     BaseNumberConverter
UInt64      UInt64Converter     BaseNumberConverter
UInt32      UInt32Converter     BaseNumberConverter
UInt64      UInt64Converter     BaseNumberConverter

DecimalConverter (as well as DoubleConverter and Int32Converter) overrides CanConvertTo to indicate it can convert to strings (because that's what base.CanConvertTo does) and all CLR primitive types. From the Reference Source:

public override bool CanConvertTo(ITypeDescriptorContext context, Type t) 
{
    if (base.CanConvertTo(context, t) || t.IsPrimitive) {
        return true;
    }
    return false;
}

decimal is NOT a primitive type from the CLR's perspective, so the converter returns false when passed typeof(decimal).

BooleanConverter does not override CanConvertTo, so it falls to the base implementation which only allows a conversion to string:

public virtual bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
{
    return (destinationType == typeof(string));
}

If you're asking why it's designed that way, then only the Framework designers can say, but I suspect it's because it's a trivial check to see if you're trying to convert from one type to the same type.

Considering that their purpose is to convert non-string types to/from strings for displaying in property grids, XAML, etc., it's not surprising that it doesn't fully support non-string conversions.