Not a dead end, but you need a depth counter. The compiler is not confused, it hit its instantiation budget, and it has no way to know your object bottoms out.
type Prev = [never, 0, 1, 2, 3, 4, 5, 6]
type Path<T, D extends number = 4> =
[D] extends [never] ? never
: T extends readonly unknown[] ? never
: T extends object
? { [K in keyof T & string]:
T[K] extends object ? K | `${K}.${Path<T[K], Prev[D]>}` : K
}[keyof T & string]
: never
The thing to internalise is that depth is not the real cost, the cross product is. Nine top keys with seven children each with six each with five is roughly 1,890 distinct string literals, and every one of them is a template literal instantiation the checker has to materialise. Add a level and you multiply, not add.
Capping at 4 means anything deeper falls back to never for the tail, which in practice you handle by accepting string past that depth. Nobody has ever complained about not getting autocomplete at level six.