As ping (more accurately, ICMP echo requests) is part of the Internet Protocol, your network stack (which is your operating system's implementation of the protocol) answers these requests.
It's neither TCP nor UDP nor any other transport protocol. In the internet header, there is a protocol field which indicates what type of payload the IP packet contains. For TCP packets that field indicates TCP. For ping packets it indicates ICMP.
Btw. this is not the only use of ICMP. E.g. when the TTL of a packet drops to zero while traveling across the net, it is discarded and the sender is notified by an ICMP packet.
If you wonder how
ping (8) manages to display received ICMP replies from user space, it does so using the socket API. This is the relevant section from the source code:
/* Initialize raw ICMP socket */
proto = getprotobyname ("icmp");
fprintf (stderr, "ping: unknown protocol icmp.\n");
fd = socket (AF_INET, SOCK_RAW, proto->p_proto);