Answer
When you call f, you are in a A<T> where T is long because B is a A<long> so T is long.
I see why it seems to be weird: you expect that T is float, but in fact since B is A<long>, B is a A<T> where T is long.
And because C is a child of B, it is an extended same type of B so a A<long>.
Therefore the result for the closed constructed type that output long and not float that was specified for the generic type parameter of the outer class.
So whatever the T specified when creating an instance, you will always get long for the type of T in f.
Solving
It's a little complicated recursive innering, I think, but don't you just simply need that?
class A<T>
{
  public class B : A<T>
  {
    public void f()
    {
      Console.WriteLine(typeof(T).ToString());
    }
    public class C : B { }
  }
}
Thus writing:
var c = new A<float>.B.C();
c.f();
Will output:
System.Single
Readings
Generics open and closed constructed types
Constructed Types
Generics in .NET
Generics (C# Programming Guide)
C# Generics Level 1
C# Generics Level 2