I think a lot more bugs are introduced from people trying to make their code too generic rather than too specific. The complexity of the code goes way up when you stop being able to rely on certain values being certain types. If I "hardcode" my ID to be an int64, there are a lot of assumptions that become safe to make, like the fact that it's a relatively small value, that I can bit shift it, that the keyspace is of a particular size.... if you then take the same code and decide that the ID should be genericized so it can be anything, now I have to account for the fact that the keyspace could be unbounded (as in the case of a string ID), I can't assume it's safe to copy around the value (it might not be thread safe and/or it might be a really large value).
Saying having less information about the data makes for easier coding is almost always not true.
> decide that the ID should be genericized so it can be anything
You say that, but you probably don't actually do it. If it truly could "be anything" then you would not be able to do anything to it. This is the nature of polymorphism.
So instead, your algorithm constrains the polymorphism based on what you need. If you make use of the properties {small, bit-shiftable, sized, bounded, copy-safe} then you must prove (exactly and only) that whatever the generic variable gets instantiated to satisfies {small, bit-shiftable, sized, bounded, copy-safe}.
Indeed, this is part of how such a system prevents bugs---it forces you to express exactly how much information about the types involved is needed. You can thus reflect better on the kinds of contracts/laws things must uphold and are prevented from accidentally making use of a property of your concrete type which you do not demarcate.
In a truly expressive language you might write
foo : forall id n .
(Bits id, Size id = n, n <= 1024)
=> id -> {Copy id} id
to indicate all of those properties needed (bounded being subsumed by constraining the size)
Today, you can get promises very similar to the above by using a language like Cryptol[0].
Ideally, the language won't permit you to make such assumptions without making them explicit. In practice, every language falls short of that, and many implementations of generics fall far short of that. Note, though, that manually implemented generics - copy-pasting and changing what you have to - isn't actually any better in this respect.
Saying having less information about the data makes for easier coding is almost always not true.