Prior to generics we relied heavily on dynamic typing via interface{}, for example:
BulkInsert(db *sql.DB, objs []interface{})
This unfortunately meant that any time you had []Foo.. you had to allocate a new []interface{} and copy over the items. Now a function like that can look like:
BulkInsert[T any](db *sql.DB, objs []T)
And we're not wasting CPU cycles to copy the slice of []Foo. I'm struggling to see how that's code smell or less excellent than using []interface{} or duplicating the code for BulkInsert for every insertable type in our application.