Understanding Index w/ Cast Given:
postgres=# \d b
                Table &quot;public.b&quot;
 Column | Type | Collation | Nullable | Default 
--------+------+-----------+----------+---------
 a      | uuid |           | not null | 
Indexes:
    &quot;b_a_idx&quot; btree (a)

postgres=# \d c
                Table &quot;public.c&quot;
 Column | Type | Collation | Nullable | Default 
--------+------+-----------+----------+---------
 a      | text |           | not null | 
Indexes:
    &quot;c_a_idx&quot; btree (a)

postgres=# explain b;
ERROR:  syntax error at or near &quot;b&quot;
LINE 1: explain b;
                ^
postgres=# analyze b; 
ANALYZE
postgres=# analyze c;
ANALYZE

Why does the following quering not use b.a's index?
postgres=# explain (select * from b join c on (b.a :: text) = c.a);
                                   QUERY PLAN                                    
---------------------------------------------------------------------------------
 Merge Join  (cost=129.05..455.25 rows=12580 width=48)
   Merge Cond: (c.a = ((b.a)::text))
   -&gt;  Index Only Scan using c_a_idx on c  (cost=0.15..64.55 rows=1360 width=32)
   -&gt;  Sort  (cost=128.89..133.52 rows=1850 width=16)
         Sort Key: ((b.a)::text)
         -&gt;  Seq Scan on b  (cost=0.00..28.50 rows=1850 width=16)
(6 rows)
Why does the following query not use b.a's index?

Because the index only stores the UUID value of a, not the result of the expression a::text
To make the index eligible for use, you would need to cast the other column to the data type stored in the index, e.g.
select * 
from b 
   join c on b.a = c.a::uuid;

Note that this doesn't guarantee that the index is used, it just makes it possible.
But as the query retrieves all rows from both tables, it's highly unlikely that the index is used anyway.