Welcome to the world of closures and captured variables 🙂
Eric Lippert has an in-depth explanation of this behaviour:
basically, it’s the loop variable that is captured, not it’s value.
To get what you think you should get, do this:
foreach (var type in types)
{
var newType = type;
var sayHello =
new PrintHelloType(greeting => SayGreetingToType(newType, greeting));
helloMethods.Add(sayHello);
}