No data is sent over the network to maintain TCP connections. You can send a network layer keep-alive simply by send()ing a zero byte packet from either peer or enable socket options to have the operating system periodically send them for you. In my opinion application layer keep-alives (your application protocol manages it) provide better design/relability than transport layer machinary.
When desinging application protocols layered on top of TCP for maximum reliability it is typically required that you incorporate some kind of non-operation (NOOP), ping, heartbeat within the protocol design.
This is very important because for example if your a server listening for a request from a client and the client is turned off after the connection is made the TCP session is essentially orphaned and your server may end up listening forever. Connection interruption cannot be detected if no data is ever sent or received!!
If the server at least sent noop/ping/heartbeats at regular intervals the outgoing request would trigger the TCP layer retrans/timeout machinary and the server would then be able to detect the dead connection. If instead your application sends an application layer "ping" or "hi, how are you?" message you can go further and use it to inquire about the state of your peer rather than simply the underlying connection.
For example if a peer is stuck in an infinite loop or its disk drives are on fire TCP keepalives alone don't help you understand and retact to the underlying problem.