diff --git a/go/types/typeutil/map.go b/go/types/typeutil/map.go
index 544246dac1c..e154be0bd60 100644
--- a/go/types/typeutil/map.go
+++ b/go/types/typeutil/map.go
@@ -12,6 +12,7 @@ import (
 	"go/types"
 	"reflect"
 
+	"golang.org/x/tools/internal/aliases"
 	"golang.org/x/tools/internal/typeparams"
 )
 
@@ -259,6 +260,9 @@ func (h Hasher) hashFor(t types.Type) uint32 {
 	case *types.Basic:
 		return uint32(t.Kind())
 
+	case *aliases.Alias:
+		return h.Hash(t.Underlying())
+
 	case *types.Array:
 		return 9043 + 2*uint32(t.Len()) + 3*h.Hash(t.Elem())
 
@@ -457,6 +461,9 @@ func (h Hasher) shallowHash(t types.Type) uint32 {
 	// elements (mostly Slice, Pointer, Basic, Named),
 	// so there's no need to optimize anything else.
 	switch t := t.(type) {
+	case *aliases.Alias:
+		return h.shallowHash(t.Underlying())
+
 	case *types.Signature:
 		var hash uint32 = 604171
 		if t.Variadic() {
diff --git a/go/types/typeutil/map_test.go b/go/types/typeutil/map_test.go
index 4891f7687d5..2cc1de786dc 100644
--- a/go/types/typeutil/map_test.go
+++ b/go/types/typeutil/map_test.go
@@ -247,6 +247,15 @@ var Issue56048 = Issue56048_I.m
 type Issue56048_Ib interface{ m() chan []*interface { Issue56048_Ib } }
 var Issue56048b = Issue56048_Ib.m
 
+// Non-generic alias
+type NonAlias int
+type Alias1 = NonAlias
+type Alias2 = NonAlias
+
+// Generic alias (requires go1.23)
+// type SetOfInt = map[int]bool
+// type Set[T comparable] = map[K]bool
+// type SetOfInt2 = Set[int]
 `
 
 	fset := token.NewFileSet()
@@ -307,6 +316,16 @@ var Issue56048b = Issue56048_Ib.m
 		Quux        = scope.Lookup("Quux").Type()
 		Issue56048  = scope.Lookup("Issue56048").Type()
 		Issue56048b = scope.Lookup("Issue56048b").Type()
+
+		// In go1.23 these will be *types.Alias; for now they are all int.
+		NonAlias = scope.Lookup("NonAlias").Type()
+		Alias1   = scope.Lookup("Alias1").Type()
+		Alias2   = scope.Lookup("Alias2").Type()
+
+		// Requires go1.23.
+		// SetOfInt    = scope.Lookup("SetOfInt").Type()
+		// Set         = scope.Lookup("Set").Type().(*types.Alias)
+		// SetOfInt2   = scope.Lookup("SetOfInt2").Type()
 	)
 
 	tmap := new(typeutil.Map)
@@ -379,6 +398,16 @@ var Issue56048b = Issue56048_Ib.m
 
 		{Issue56048, "Issue56048", true},   // (not actually about generics)
 		{Issue56048b, "Issue56048b", true}, // (not actually about generics)
+
+		// All three types are identical.
+		{NonAlias, "NonAlias", true},
+		{Alias1, "Alias1", false},
+		{Alias2, "Alias2", false},
+
+		// Generic aliases: requires go1.23.
+		// {SetOfInt, "SetOfInt", true},
+		// {Set, "Set", false},
+		// {SetOfInt2, "SetOfInt2", false},
 	}
 
 	for _, step := range steps {
diff --git a/go/types/typeutil/methodsetcache.go b/go/types/typeutil/methodsetcache.go
index a5d9310830c..bd71aafaaa1 100644
--- a/go/types/typeutil/methodsetcache.go
+++ b/go/types/typeutil/methodsetcache.go
@@ -9,6 +9,8 @@ package typeutil
 import (
 	"go/types"
 	"sync"
+
+	"golang.org/x/tools/internal/aliases"
 )
 
 // A MethodSetCache records the method set of each type T for which
@@ -32,12 +34,12 @@ func (cache *MethodSetCache) MethodSet(T types.Type) *types.MethodSet {
 	cache.mu.Lock()
 	defer cache.mu.Unlock()
 
-	switch T := T.(type) {
+	switch T := aliases.Unalias(T).(type) {
 	case *types.Named:
 		return cache.lookupNamed(T).value
 
 	case *types.Pointer:
-		if N, ok := T.Elem().(*types.Named); ok {
+		if N, ok := aliases.Unalias(T.Elem()).(*types.Named); ok {
 			return cache.lookupNamed(N).pointer
 		}
 	}