Strictly speaking, a self-join is just a relationship between two TOs from the same table; it doesn't specify the type of relationship. Joining on the primary key will only show you the Contractor record you're already on, which has its uses, but not in this case.
What you can do is create a pick list – e.g. use a portal pointing at a Cartesian (x) self-join – of all Contractors; pick one to put their ID into a global field (say, gSelectedContractorForContacts) and use that to filter into the contact's foreign contractorID. (Or use a static value list of your Contractor IDs/names and use it to format the global field as a popup/dropdown, though that may be of limited usability.)
So you have
• a picker relationship (Cartesian) between two Contractors TOs for a selection portal (or a value list), and
• a filtered relationship between Contractors::gSelectedContractorForContacts = Contacts::contractorID_FK
Using the portal approach and the right script, you could utilize the global field as a multikey to select multiple Contractor IDs and show all their associated contacts.