Depending on how MetricCategory.Async.toString() is implemented the outcome of the operation might be arbitrary. Consider following example:
class MetricCategory {
    object Async {
        override fun toString(): String {
            return "Async"
        }
    }
}
This implementation would result in true, true printed out. As documented the === operator compares referential equality: 
evaluates to true if and only if a and b point to the same object.
But why are the 2 constant string expressions the same object? This is caused by a feature of JVM (and other runtimes) called string interning:
In computer science, string interning is a method of storing only one
  copy of each distinct string value, which must be immutable. Interning
  strings makes some string processing tasks more time- or
  space-efficient at the cost of requiring more time when the string is
  created or interned. The distinct values are stored in a string intern
  pool.
String interning does not happen automatically in JVM but it can be triggered manually. 
class MetricCategory {
    object Async {
        override fun toString(): String {
            val result = "a".toUpperCase() + "SYNC".toLowerCase()
            return result.intern()
        }
    } 
 }
The above example would print true, true again but only because we've called String.intern.
Consider below examples:
println("Async" == "Async") // true, obviously
println("Async" === "Async") // true, string interning for literals
println("Async" == java.lang.String("Async").toString())// true, obviously
println("Async" === java.lang.String("Async").toString()) // false, new instance on the right
println("Async" === java.lang.String("Async").toString().intern()) // true, right changed to shared instance
Further reading: