I believe when you set detect_types to both PARSE_DELCTYPES and PARSE_COLNAMES it prioritizes the column names first, then the declared types. Since your declared type of my_col is INTEGER, and you only declared a converter for "BOOLEAN" my_col as "my_col float [FLOAT]" Because of the column name it looks for a converter for "FLOAT" and doesn't find it. Since "my_col" is a bare column it checks for a converter for "INTEGER" and doesn't find it. So it returns what it got from the query, which is 1 CAST(my_col as FLOAT) as [my_col cast float] The column name "my_col cast float" doesn't conform to the "name [type]" format, so no check is done for a converter on the column name. CAST(my_col as FLOAT) is not a bare column any more, so there is no declared type for it to look up a converter for. So it returns what it got from the query, which is my_col cast as a float, or 1.0 my_col as "my_col bol [BOOLEAN]" The column name of the correct format, so it checks for a converter for "BOOLEAN" and finds it. It passes what it got from the query (1) to your registered function for "BOOLEAN" and gets back True CAST(my_col as BOOLEAN) as [my_col cast bol] The column name "my_col cast bol" doesn't conform to the "name [type]" format, so no check is done for a converter on the column name. CAST(my_col as BOOLEAN) isn't a bare column any more, so there is no declared type for it to look up a converter for. So it returns what it got from the query, which is my_col cast to the SQLite type of "BOOLEAN", which following the rules results in numeric affinity. 1 as numeric is still 1, so that's what you get back. So the important things for you is that for PARSE_DECLTYPES when you do... cast(my_col as SOMETHING) ...that "SOMETHING" is not carried through as the declared type. PARSE_DECLTYPES only works if it's selecting just a bare column from a table. And for PARSE_COLNAMES, your column names need to follow the format of "name [type]"