How do TreeMap and TreeSet stay sorted in Java, and what data structure do they use?
Both are backed by a red-black tree, a self-balancing binary search tree. The tree invariant is that every node's key is greater than all keys in its left subtree and less than all keys in its right subtree, which makes lookup, insertion and deletion O(log n) rather than the O(n) of a sorted list. The red-black colouring is what keeps the tree balanced: after every insertion or deletion the algorithm recolours and rotates nodes so that the longest path from the root to a leaf never exceeds twice the shortest, which is what stops a naive binary search tree from degenerating into a list.
The practical difference from a HashMap is the ordering guarantee. A TreeMap iterates in sorted key order and a TreeSet in sorted element order, every time, with no extra work. That makes them the right choice for range queries — everything between two keys, everything greater than a key — because the tree structure supports them directly, whereas a HashMap would require scanning the entire entry set.
The cost is that comparison is not free. Each operation performs O(log n) comparisons, and each comparison runs your comparator or your Comparable implementation. A HashMap computes a hash once and then compares a handful of candidates; a TreeMap compares on every step of the descent.
Two more details worth knowing. TreeMap and TreeSet reject null keys — a null has no position in an ordering. And the iteration order of a TreeMap is the sorted order of its keys, not the order of insertion, which is the first thing people check when they are surprised by an unexpectedly sorted output.