This feels like something that should live in generic.py