This is a relatively hard problem, see e.g. the discussion on Stripping parameter from parametric types here on discourse, or the paragraph on Design Patterns with Parametric Methods in the documentation.
I would think that building a separate method for each family remains the most idiomatic solution. This is more or less what similar does, for example.
That being said, if you really want a fully generic implementation, something like this might work:
stripped_type(x) = stripped_type(typeof(x))
stripped_type(typ::DataType) = Base.typename(typ).wrapper
For example:
julia> struct A{T}
x::T
end
julia> a = A(42)
A{Int64}(42)
julia> stripped_type(a)(42.5)
A{Float64}(42.5)
Again, I would not recommend such a solution, which relies too much on internal details to my taste.