Note that with some find implementations on some systems (including GNU find on GNU systems), * may fail to match parts of file names that are not valid text in the current locale.
For example, the command above would find /stéphane/X even though s is not an uppercase letter if that é was encoded in iso8859-1 and the current locale was using UTF-8 as its charmap (where the 0xe9 byte there could not be decoded into a character so * couldn't match across it), and the first command would fail to find /Stéphane/X for the same reason.
zsh globs don't have this kind of problem as the treat each byte that can't be decoded into a character as if it was an undefined character, so you could do:
print -rC1 /[[:upper:]]*/**/X(ND/)
Or as a slight optimisation if you don't need the list to be ordered:
print -rC1 /[[:upper:]]*/**/X(ND/oN)
Note that it would include /SymLink/.../X dirs. To avoid that:
(){print -rC1 $^@/**/X(ND/oN)} /[[:upper:]]*(N/oN)
or:
print -rC1 /[[:upper:]]*(N/oNe['reply=($REPLY/**/X(ND/oN)'])
Which are like the two stage find approaches: find the directories whose name starts with an uppercase letter in one glob and then all the X dirs in them as separate globs.