The key point is, if your method promises to return whatever the caller wishes, I could write:

Date date=box.get("key");

but also

String str=box.get("key");
String[] obj=box.get("key");

As all these types, Date, String, or String[] are assignable to Serializable. Less intuitively, you can even write

Object[] obj=box.get("key");

despite Object[] is not Serializable, because there could be a subtype of Object[] that is Serializable. So the compiler will infer Object[] & Serializable for T (see also here).

The difference between Java 7 and Java 8 is that the Java 7 compiler did not perform this type inference when you put this method invocation as an argument to another invocation (aka “nested method call”). It always used the bounds of the type parameter, i.e. Serializable and found that it has to perform a varargs invocation.

In contrast, Java 8 considers all possibilities. It can infer a non-array type and perform a varargs invocation, but it can also infer an array type and pass it directly to the method String.format(String,Object[]). The rules are simple, a non-vararg invocation is always preferred.

By the way, referring to Serializable explicitly has no real benefit. There are plenty of place, where serializable objects are returned, see Collections.emptyList(), for example, without declaring Serializable. Consequently, the JRE classes never refer to Serializable this way either. Most notably, not even ObjectOutputStream.writeObject(…) refers to Serializable in its signature, but just accepts Object.