First, you should use isconcretetype on types such as TypeHolder{Float16}, not values (such as holder in your example):
isconcretetype(typeof(holder)) # true
but then this does not give you much information: by definition of what a concrete type is, the type of holder will always be concrete (since there exists a value, holder, having this type).
I’m actually not sure of what exactly you’re trying to achieve here, but there’s probably no need to store the type as a field in the struct: having it as a type parameter makes it possible to retrieve it when you need it. A minimal example could look like:
struct TypeHolder{T<:Real}
function TypeHolder(::Type{T}) where {T<:Real}
return new{T}()
end
end
holder = TypeHolder(Float16) # TypeHolder{Float16}
isconcretetype(typeof(holder)) # true (by definition)
# a function that needs to know about T in order to build a buffer
function compute(x::TypeHolder{T}) where {T}
buffer = Vector{T}(undef, 10)
do_something_with(buffer)
end