The actual public key used for logging in to a specific site is completely random.
Optionally, the website can ask for "attestation", which is intended to prove that the public key is from a specific vendor/model. To make this also unlinkable, devices are supposed to share attestation keys in batches of 100k units.
I'm not so sure they cannot associate.
So somesite.example if it suspects Jim and Candy are the same person, or at least, using the same FIDO authenticator, could do this:
When Jim signs in, they present Candy's ID. If they're right, Jim's authenticator goes "Oh I recognise this, signed". If they're wrong, Jim gets an error. Weird. Presumably on a second try they give Jim's ID and it works so that Jim isn't too suspicious.
So this attack would allow a site that strongly suspects you're doing this to prove it, to their own satisfaction anyway. But it doesn't offer any practical way for a site with more than a handful of users to just match all the users.
In resident mode, you have to admit who you are as part of signing in - you're not separately typing in an email address or username or whatever, you just press the button on your authenticator (or touch the sensor on your phone, or whatever) and you're in. This obviously means it doesn't make sense for Jim and Candy to use one device for two users on the site, and most likely their device will prohibit them from trying to enroll the second user this way.
Edited to add: If someothersite.example plays Jim or Candy's IDs from somesite.example (may it's secretly run by the same people, or they stole a database backup) to Jim (or Candy) they don't work, the IDs are bound to the domain, so these don't match.
Maybe I made a mistake, but Firefox doesn't seem to work very reliably with it, and mobile support is spotty too.
When you register your key on a service, the service sends an application identifier down. Your key then creates a fresh key pair and sends a handle (name for that keypair) and the public key back to the service. Later when you authenticate, the service sends down the handle and challenge. Your key uses the handle to find the right private key and sign the challenge, which is checked by the service using the public key to confirm that you do indeed possess the private key.
Since fresh keypairs (and handles) are generated each time you register a key, the service can't use the registration process to identify whether you're re-using a physical key (it should look no different from using a new physical key).
Alternatively, a service can check if your physical key contains other handles by initiating requests with them, but this will almost always be very obvious. E.g. If they suspect you are Bob, they could request a challenge with _Bob's_ handle.
But they can't just spray handles, since if they do this when you're not expecting to authenticate anything, it will be quite obvious: your key, and any intermediate applications like the browser or OS, will behave like they are authenticating. With a well implemented key, you will be safe as long as you don't touch the key on spurious authentication attempts. The service won't be able to tell whether the key doesn't have the handle (and is ignoring the challenge) or if the key does have it but you just didn't touch the key because you weren't expecting an authentication request.
This leaves the service with the final option of only doing the test while you're trying to log into what they suspect is an alternate account. That means they can only do one check and will have to be fairly certain about you being Bob lest you be tipped off. If they guess right, you won't be able to tell a difference but the service will know that you can authenticate with Bob's handle while trying to log in as Alice. If they guess wrong however, you might become suspicious since the authentication will fail and in a non-standard way (e.g. the key can indicate that it has received a foreign handle).
All this means is that, if the service is trying to tie identities to "serve ads", they won't have a feasible way to do this with U2F. But, if it's a threat actor with nation state level resources and lots of time then... well... nothing consumer level will really help you (though U2F still puts up a decent fight).
Yubikey outlines their method here[1]. They generate a different keypair for each website public key and have the server store an encrypted and authenticated copy of the private key using a single on-device key. So baring breaking the underlying primitives the server will only have a site-specific public key and a site-specific encrypted blob.
[1]: https://developers.yubico.com/U2F/Protocol_details/Key_gener...